go-gRPC-1

日之朝矣

开发环境安装

安装gRPC

1
go get google.golang.org/grpc@latest

安装Protocol Buffers

https://github.com/protocolbuffers/protobuf/releases 下载一份对应操作系统的protoc 比如windows64位下载protoc-22.1-win64.zip,解压到自己找的到的地方

将该目录下的bin目录添加到环境变量中

使用protoc --version检查是否安装完成

安装protoc-gen-go

1
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest

该插件会根据.proto文件生成一个后缀为.pb.go的文件,包含所有.proto文件中定义的类型及其序列化方法。

使用protoc-gen-go --version检查是否安装成功

安装 grpc插件

1
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest

该插件会生成一个后缀为_grpc.pb.go的文件,其中包含:

  • 一种接口类型(或存根) ,供客户端调用的服务方法。
  • 服务器要实现的接口类型。

使用protoc-gen-go-grpc --version检查是否安装成功

上述命令会默认将插件安装到$GOPATH/bin,为了protoc编译器能找到这些插件,请确保你的$GOPATH/bin在环境变量中。

开始

三个步骤:

  1. 编写.proto文件定义服务
  2. 生成指定语言的代码
  3. 编写业务逻辑代码

编写.proto文件定义服务

首先找个地方编写一个创建一个.proto文件,例如创建一个pb文件夹,里面新建一个add.proto文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// add.proto
syntax = "proto3"; // 版本声明

option go_package = "AddRpc_client/pb";

package pb;

service Calc{
rpc Add (CalcRequest) returns (CalcResponse){} //服务要实现的方法
}

message CalcRequest{
int64 x = 1;
int64 y = 2;
}

message CalcResponse{
string reply = 1;
}

生成代码

需要生成两份代码,一份放到服务端,一份放到客户端

将上一步编写好的.proto文件复制一下分别放到服务端项目代码,客户端项目代码下,最好是建个文件夹(比如上一步的pb文件夹),让生成的代码自动放入文件夹

两个项目下都执行如下内容区生成Go代码,如果需要其他语言的代码,可以去查一下对应的生成方式

1
protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative pb/add.proto

这时我们会发现pb文件夹内多出了两个go文件,add.pb.goadd_grpc.pb.go这就是生成的代码

再执行go mod tidy去同步下依赖

编写业务逻辑

服务端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// main.go

package main

import (
"AddRpc_server/pb"
"context"
"google.golang.org/grpc"
"log"
"net"
"strconv"
)

type server struct {
pb.UnimplementedCalcServer
}

// 实现`.proto`中描述的方法
func (s *server) Add(ctx context.Context, in *pb.CalcRequest) (*pb.CalcResponse, error) {
return &pb.CalcResponse{Reply: strconv.FormatInt(in.X+in.Y, 10)}, nil
}

func main() {
// 监听端口
listen, err := net.Listen("tcp", ":4567")
if err != nil {
log.Fatalf("net.Listen err: %v", err)
}
s := grpc.NewServer() // grpc创建服务器
pb.RegisterCalcServer(s, &server{}) // 注册服务
err = s.Serve(listen)
if err != nil {
log.Printf("s.Serve err: %v", err)
return
}
}

我们在 server这个结构体中,使用了pb.UnimplementedCalcServer,通过使用他,可以避免因为未实现方法导致的程序出错

如果我们忘记了如何去定义方法头,可以进入pb.UnimplementedCalcServer中去复制一下

需要实现的方法也就是我们的业务代码,在上述代码中也就是func (s *server) Add(ctx context.Context, in *pb.CalcRequest) (*pb.CalcResponse, error) {...}这部分内容

客户端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package main

import (
"AddRpc_client/pb"
"context"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
"log"
"time"
)

func main() {
// 创建连接
conn, err := grpc.Dial("127.0.0.1:4567", grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
return
}
defer conn.Close()

client := pb.NewCalcClient(conn)

ctx, cancelFunc := context.WithTimeout(context.Background(), time.Second)
defer cancelFunc()

resp, err := client.Add(ctx, &pb.CalcRequest{
X: 10,
Y: 20,
})
if err != nil {
log.Fatalf("client.Add(*) ")
}
log.Printf("resp: %v", resp.Reply)
}

这样我们便算是完成了,启动服务端,然后启动客户端看看效果

1
2023/04/10 16:10:36 resp: 30

出结果了

当然如果使用其他语言编写客户端也是可以的

  • 标题: go-gRPC-1
  • 作者: 日之朝矣
  • 创建于 : 2023-04-10 16:07:19
  • 更新于 : 2023-10-10 08:35:51
  • 链接: https://rzzy.fun/2023/04/10/go-gRPC-1/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
 评论