Go使用gRPC进行通信

RPC是远程过程调用的简称,是分布式系统中不同节点间流行的通信方式。

安装gRPCProtoc

安装protobuf

1
2
3
go get -u google.golang.org/protobuf
go get -u google.golang.org/protobuf/proto
go get -u google.golang.org/protobuf/protoc-gen-go

安装Protoc

1
2
# 下载二进制文件并添加至环境变量
https://github.com/protocolbuffers/protobuf/releases

安装Protoc插件protoc-gen-go

1
2
# go install 会自动编译项目并添加至环境变量中
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
1
2
#protoc-gen-go 文档地址
https://developers.google.com/protocol-buffers/docs/reference/go-generated

创建proto文件并定义服务

新建 task.proto文件

1
touch task.proto

编写task.proto

 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
// 指定proto版本
syntax = "proto3";
// 指定包名
package task;
// 指定输出 go 语言的源码到哪个目录和 包名
// 主要 目录和包名用 ; 隔开
// 将在当前目录生成 task.pb.go
// 也可以只填写 "./",会生成的包名会变成 "----"
option go_package = "./;task";

// 指定RPC的服务名
service TaskService {
    // 调用 AddTaskCompletion 方法
    rpc AddTaskCompletion(request) returns (response);
}

// RPC TaskService服务,AddTaskCompletion函数的请求参数,即消息
message request {
    uint32 id = 1;//任务id
    string module = 2;//所属模块
    int32  value = 3;//此次完成值
    string guid = 4;//用户id
}
// RPC TaskService服务,TaskService函数的返回值,即消息
message response{

}

使用Protoc来生成Go代码

1
2
3
protoc --go_out=. --go-grpc_out=. <要进行生成代码的文件>.proto
# example
protoc --go_out=. --go-grpc_out=. .\task.proto

这样生成会生成两个.go文件,一个是对应消息task.pb.go,一个对应服务接口task_grpc.pb.go

task_grpc.pb.go中,在我们定义的服务接口中,多增加了一个私有的接口方法: mustEmbedUnimplementedTaskServiceServer()

使用Go监听gRPC服务端及客户端

监听服务端

并有生成的一个UnimplementedTaskServiceServer结构体来实现了所有的服务接口。因此,在我们自己实现的服务类中,需要继承这个结构体,如:

 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
// 用于实现grpc服务 TaskServiceServer 接口
type TaskServiceImpl struct {
    // 需要继承结构体 UnimplementedServiceServer 或mustEmbedUnimplementedTaskServiceServer
	task.mustEmbedUnimplementedTaskServiceServer()
}

func main() {
	// 创建Grpc服务
	// 创建tcp连接
	listener, err := net.Listen("tcp", ":8082")
	if err != nil {
		fmt.Println(err)
		return
	}
	// 创建grpc服务
	grpcServer := grpc.NewServer()
	// 此函数在task.pb.go中,自动生成
	task.RegisterTaskServiceServer(grpcServer, &TaskServiceImpl{})
	// 在grpc服务上注册反射服务
	reflection.Register(grpcServer)
	// 启动grpc服务
	err = grpcServer.Serve(listener)
	if err != nil {
		fmt.Println(err)
		return
	}

}

func (s *TaskServiceImpl) AddTaskCompletion(ctx context.Context, in *task.Request) (*task.Response, error) {
	fmt.Println("收到一个Grpc 请求, 请求参数为", in.Guid)
	r := &task.Response{
	}
	return r, nil
}

然后在TaskService上实现我们的服务接口。

客户端

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
	conn, err := grpc.Dial("127.0.0.1:8082", grpc.WithInsecure())
	if err != nil {
		panic(err)
	}
	defer conn.Close()
	// 创建grpc客户端
	client := task.NewTaskServiceClient(conn)
	// 创建请求
	req := &task.Request{
		Id:     1,
		Module: "test",
		Value:  3,
		Guid:   "test",
	}
	// 调用rpc TaskService AddTaskCompletion函数
	response, err := client.AddTaskCompletion(context.Background(), req)
	if err != nil {
		log.Println(err)
		return
	}
	log.Println(response)

本文参考

Licensed under CC BY-NC-SA 4.0