Go中的gRPC入门教程详解

Go中的gRPC入门教程详解

什么是gRPC?

gRPC是一种高性能、通用的开源框架,用于构建分布式系统。它由Google公司推出,基于Protocol Buffers(一种高效的序列化技术)开发,支持多种语言(如Go、Java、Python等)。gRPC主要解决了分布式系统中服务间通信的问题,极大地简化了开发人员的工作量。

基本概念

在了解gRPC的使用之前,我们需要了解一些基本概念:

  • 服务定义:定义服务的接口和方法。
  • 消息:通过Protocol Buffers定义的数据结构,用于在客户端和服务端之间传输数据。
  • 客户端:调用远程服务的一方。
  • 服务端:提供服务的一方。

安装

使用Go语言开发gRPC应用,需要安装以下两个库:

  • protoc:Protocol Buffers编译器。
  • gRPC:Go中的gRPC库。

安装方法可以参考这个网站:https://grpc.io/docs/languages/go/quickstart/

编写服务定义文件

服务定义文件使用Protocol Buffers语言编写,包含服务和消息的定义内容。以下是一个服务定义文件的示例:

syntax = "proto3";

package helloworld;

service Greeter {
  rpc SayHello (HelloRequest) returns (HelloReply) {}
}

message HelloRequest {
  string name = 1;
}

message HelloReply {
  string message = 1;
}

上述文件定义了一个Greeter服务,包括一个SayHello方法和两个消息类型:HelloRequest和HelloReply。SayHello方法接收一个HelloRequest消息,并返回一个HelloReply消息。

编写服务端

服务端代码主要负责注册服务、实现服务接口的具体方法。以下是一个gRPC服务端的示例代码:

package main

import (
    "context"
    "log"
    "net"

    pb "github.com/your_username/your_project/your_proto_file_directory"
    "google.golang.org/grpc"
)

const (
    port = ":50051"
)

type server struct{}

func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
    log.Printf("Received: %v", in.GetName())
    return &pb.HelloReply{Message: "Hello " + in.GetName()}, nil
}

func main() {
    lis, err := net.Listen("tcp", port)
    if err != nil {
        log.Fatalf("failed to listen: %v", err)
    }
    s := grpc.NewServer()
    pb.RegisterGreeterServer(s, &server{})
    if err := s.Serve(lis); err != nil {
        log.Fatalf("failed to serve: %v", err)
    }
}

上述代码定义了一个名为Greeter的服务,包含一个SayHello方法。通过pb.RegisterGreeterServer(s, &server{})将服务注册到grpc服务器中。

编写客户端

客户端代码主要负责调用服务端提供的接口。以下是一个gRPC客户端的示例代码:

package main

import (
    "context"
    "log"
    "os"
    "time"

    pb "github.com/your_username/your_project/your_proto_file_directory"
    "google.golang.org/grpc"
)

const (
    address     = "localhost:50051"
    defaultName = "world"
)

func main() {
    conn, err := grpc.Dial(address, grpc.WithInsecure(), grpc.WithBlock())
    if err != nil {
        log.Fatalf("did not connect: %v", err)
    }
    defer conn.Close()
    c := pb.NewGreeterClient(conn)

    name := defaultName
    if len(os.Args) > 1 {
        name = os.Args[1]
    }
    ctx, cancel := context.WithTimeout(context.Background(), time.Second)
    defer cancel()
    r, err := c.SayHello(ctx, &pb.HelloRequest{Name: name})
    if err != nil {
        log.Fatalf("could not greet: %v", err)
    }
    log.Printf("Greeting: %s", r.GetMessage())
}

上述代码定义了一个Greeter客户端,通过pb.NewGreeterClient(conn)创建一个客户端实例。然后调用该实例的SayHello方法,向服务端发送一个HelloRequest消息,并接收其返回的HelloReply消息。

示例说明

以下是两个示例说明:

示例一

一个简单的计算器服务,实现add和multiply两个方法。

服务定义文件calculator.proto:

syntax = "proto3";

package calculator;

service Calculator {
    rpc Add (Numbers) returns (Number) {}
    rpc Multiply (Numbers) returns (Number) {}
}

message Numbers {
    int32 num1 = 1;
    int32 num2 = 2;
}

message Number {
    int32 result = 1;
}

服务端代码:

package main

import (
    "context"
    "log"
    "net"

    pb "github.com/your_username/calculator"
    "google.golang.org/grpc"
)

const (
    port = ":50051"
)

type server struct{}

func (s *server) Add(ctx context.Context, in *pb.Numbers) (*pb.Number, error) {
    result := in.Num1 + in.Num2
    return &pb.Number{Result: result}, nil
}

func (s *server) Multiply(ctx context.Context, in *pb.Numbers) (*pb.Number, error) {
    result := in.Num1 * in.Num2
    return &pb.Number{Result: result}, nil
}

func main() {
    lis, err := net.Listen("tcp", port)
    if err != nil {
        log.Fatalf("failed to listen: %v", err)
    }
    s := grpc.NewServer()
    pb.RegisterCalculatorServer(s, &server{})
    if err := s.Serve(lis); err != nil {
        log.Fatalf("failed to serve: %v", err)
    }
}

客户端代码:

package main

import (
    "context"
    "log"
    "os"
    "time"

    pb "github.com/your_username/calculator"
    "google.golang.org/grpc"
)

const (
    address     = "localhost:50051"
    defaultNum1 = 2
    defaultNum2 = 3
)

func main() {
    conn, err := grpc.Dial(address, grpc.WithInsecure(), grpc.WithBlock())
    if err != nil {
        log.Fatalf("did not connect: %v", err)
    }
    defer conn.Close()
    c := pb.NewCalculatorClient(conn)

    num1 := defaultNum1
    num2 := defaultNum2
    if len(os.Args) > 1 {
        num1 = int32(os.Args[1])
        num2 = int32(os.Args[2])
    }
    ctx, cancel := context.WithTimeout(context.Background(), time.Second)
    defer cancel()
    r1, err := c.Add(ctx, &pb.Numbers{Num1: num1, Num2: num2})
    if err != nil {
        log.Fatalf("could not add: %v", err)
    }
    r2, err := c.Multiply(ctx, &pb.Numbers{Num1: num1, Num2: num2})
    if err != nil {
        log.Fatalf("could not multiply: %v", err)
    }
    log.Printf("Add result: %d", r1.GetResult())
    log.Printf("Multiply result: %d", r2.GetResult())
}

示例二

一个简单的文件传输服务,实现Upload和Download两个方法。

服务定义文件file.proto:

syntax = "proto3";

package file;

service File {
    rpc Upload (FileInfo) returns (Response) {}
    rpc Download (Request) returns (FileInfo) {}
}

message Request {
    string name = 1;
}

message FileInfo {
    bytes content = 1;
    string name = 2;
}

message Response {
    string message = 1;
}

服务端代码:

package main

import (
    "context"
    "io/ioutil"
    "log"
    "net"

    pb "github.com/your_username/file"
    "google.golang.org/grpc"
)

const (
    port = ":50051"
)

type server struct{}

func (s *server) Upload(ctx context.Context, in *pb.FileInfo) (*pb.Response, error) {
    err := ioutil.WriteFile(in.GetName(), in.GetContent(), 0644)
    if err != nil {
        log.Fatalf("Failed to save file: %v", err)
    }
    return &pb.Response{Message: "File uploaded successfully!"}, nil
}

func (s *server) Download(ctx context.Context, in *pb.Request) (*pb.FileInfo, error) {
    content, err := ioutil.ReadFile(in.GetName())
    if err != nil {
        log.Fatalf("Failed to read file: %v", err)
    }
    return &pb.FileInfo{Content: content, Name: in.GetName()}, nil
}

func main() {
    lis, err := net.Listen("tcp", port)
    if err != nil {
        log.Fatalf("failed to listen: %v", err)
    }
    s := grpc.NewServer()
    pb.RegisterFileServer(s, &server{})
    if err := s.Serve(lis); err != nil {
        log.Fatalf("failed to serve: %v", err)
    }
}

客户端代码:

package main

import (
    "context"
    "io/ioutil"
    "log"
    "os"

    pb "github.com/your_username/file"
    "google.golang.org/grpc"
)

const (
    address     = "localhost:50051"
    defaultFile = "test.txt"
)

func main() {
    conn, err := grpc.Dial(address, grpc.WithInsecure())
    if err != nil {
        log.Fatalf("did not connect: %v", err)
    }
    defer conn.Close()
    c := pb.NewFileClient(conn)

    file := defaultFile
    if len(os.Args) > 1 {
        file = os.Args[1]
    }
    content, err := ioutil.ReadFile(file)
    if err != nil {
        log.Fatalf("Failed to read file: %v", err)
    }
    ctx := context.Background()

    _, err = c.Upload(ctx, &pb.FileInfo{Content: content, Name: file})
    if err != nil {
        log.Fatalf("Failed to upload file: %v", err)
    }
    log.Printf("File uploaded successfully!")

    r, err := c.Download(ctx, &pb.Request{Name: file})
    if err != nil {
        log.Fatalf("Failed to download file: %v", err)
    }
    err = ioutil.WriteFile(file, r.GetContent(), 0644)
    if err != nil {
        log.Fatalf("Failed to save file: %v", err)
    }
    log.Printf("File downloaded successfully!")
}

以上就是Go中gRPC入门教程的详解,希望能对您有所帮助。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Go中的gRPC入门教程详解 - Python技术站

(0)
上一篇 2023年6月3日
下一篇 2023年6月3日

相关文章

  • ASP.NET CORE读取json格式配置文件

    ASP.NET Core 读取 JSON 格式配置文件的流程: 在 appsettings.json 文件中定义所需的配置项。 在 Program.cs 文件中使用 CreateDefaultBuilder(args) 方法创建 IHostBuilder 对象,并在 ConfigureAppConfiguration(…) 方法中添加读取配置文件的功能。…

    C# 2023年6月3日
    00
  • C#创建自签名认证文件的方法

    下面为您详细讲解C#创建自签名认证文件的方法的完整攻略。 什么是自签名认证文件 自签名认证文件是用来对软件代码进行签名的一种证书,用于保证软件代码的来源和完整性。 C#中也支持使用自签名认证文件对程序集进行签名,使程序能够在运行时通过CAS(代码访问安全性)校验。 创建自签名认证文件的步骤 第一步:生成证书文件 可以使用makecert工具来生成自签名证书文…

    C# 2023年6月1日
    00
  • C# winform打开Excel文档的方法总结(必看篇)

    以下是对“C# winform打开Excel文档的方法总结(必看篇)”的完整攻略: 简介 在C# WinForm开发中,我们经常需要读取并操作Excel文档。本文将介绍几种可行的Excel文档打开方法。 使用OleDb方式打开Excel文档 用Visual Studio创建一个新的WinForm程序项目,引用System.Data.OleDb应用程序集。 在…

    C# 2023年6月1日
    00
  • 详解C#中 Thread,Task,Async/Await,IAsyncResult的那些事儿

    详解C#中 Thread,Task,Async/Await,IAsyncResult的那些事儿 多线程编程是现代软件开发中非常重要的一个方向。在C#中,有多种方式来进行多线程编程,其中 Thread,Task,Async/Await,IAsyncResult 是最常用的几种方式。 Thread Thread 表示线程类。它允许我们在应用程序中创建新线程来执行…

    C# 2023年6月6日
    00
  • 记录.Net部署Docker-v指令使用

    记录Docker的-v指令使用 前言 之前我浅学了一下docker,方便部署.net项目(部署的是打包之后的项目) dockerfile文件如下: FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base WORKDIR /app EXPOSE 5031 EXPOSE 7031 FROM mcr.microsoft.c…

    C# 2023年4月25日
    00
  • IIS部署ASP.NET Core项目及常见问题总结

    IIS部署ASP.NET Core项目及常见问题总结 ASP.NET Core是一个跨平台的Web应用程序框架,可以在Windows、Linux和macOS上运行。在本攻略中,我们将讨论如何在IIS上部署ASP.NET Core项目,并总结一些常见问题及其解决方案。 步骤一:安装.NET Core Runtime和.NET Core Hosting Bund…

    C# 2023年5月17日
    00
  • 一文看懂C#中List的扩容机制

    下面来详细讲解一下“一文看懂C#中List的扩容机制”的完整攻略。 1. 背景 在C#中,List是一个非常常用的集合类型。很多人可能会关心List的扩容机制。因为在使用List时,如果不理解List的扩容机制,在添加元素时可能会造成一些性能上的问题。所以本文就来详细讲解一下C#中List的扩容机制。 2. List的扩容机制 在List中,扩容是通过数组的…

    C# 2023年6月1日
    00
  • C#中LINQ to DataSet操作及DataTable与LINQ相互转换

    下面是详细讲解“C#中LINQ to DataSet操作及DataTable与LINQ相互转换”的完整攻略。 什么是LINQ to DataSet LINQ to DataSet是一组可嵌入到.NET语言中的代码库,使得我们可以在C#或VB.NET中使用LINQ查询DataSet或DataTable的数据。 如何进行LINQ to DataSet操作 我们可…

    C# 2023年5月15日
    00
合作推广
合作推广
分享本页
返回顶部