- Added package.json to manage development scripts. - Updated restart-services.ps1 to call the new dev script for starting services. - Refactored start-admin.ps1, start-backend.ps1, start-frontend.ps1, and start-mcp.ps1 to utilize the dev script for starting respective services. - Enhanced stop-services.ps1 to improve process termination logic by matching command patterns.
4.0 KiB
4.0 KiB
title, description, date, draft, slug, image, categories, tags
| title | description | date | draft | slug | image | categories | tags | |||
|---|---|---|---|---|---|---|---|---|---|---|
| Go使用gRPC进行通信 | RPC是远程过程调用的简称,是分布式系统中不同节点间流行的通信方式。 | 2022-05-26T14:17:33+08:00 | false | go-grpc |
|
|
安装gRPC和Protoc
安装protobuf
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
# 下载二进制文件并添加至环境变量
https://github.com/protocolbuffers/protobuf/releases
安装Protoc插件protoc-gen-go
# go install 会自动编译项目并添加至环境变量中
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
#protoc-gen-go 文档地址
https://developers.google.com/protocol-buffers/docs/reference/go-generated
创建proto文件并定义服务
新建 task.proto文件
touch task.proto
编写task.proto
// 指定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代码
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结构体来实现了所有的服务接口。因此,在我们自己实现的服务类中,需要继承这个结构体,如:
// 用于实现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上实现我们的服务接口。
客户端
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)