【Golang | gRPC】gRPC-Client Streaming客户端流实战
环境:
Golang: go1.18.2 windows/amd64
grpc: v1.47.0
protobuf: v1.28.0
完整代码:
https://github.com/WanshanTian/GolangLearning
cd GolangLearning/RPC/gRPC-ClientStreaming
1. 简介
前文【Golang | gRPC】HTTP的连接管理——从HTTP/1.0到HTTP/2.0的演进 简单介绍了gRPC中流模式主要分为客户端流、服务端流、双向流以及流传输模式的优点,下面通过一个demo来说明gRPC客户端流的使用
2. 实践
现有下面一种场景:服务端保存着用户的年龄信息,客户端通过stream
多次发送含用户姓名的message
,服务端通过stream
接收message
,一次性返回所有请求用户的年龄和
2.1 proto文件
2.1.1 新建gRPC-ClientStreaming文件夹,使用go mod init
初始化,创建pb文件夹,新建query.proto文件
syntax = "proto3";
package pb;
option go_package= ".;pb";// 定义查询服务包含的方法
service Query {// 客户端流模式rpc GetAge (stream userInfo) returns (ageInfo){}
}// 请求用的结构体,包含一个name字段
message userInfo {string name = 1;
}// 响应用的结构体,包含一个age字段
message ageInfo {int32 age = 1;
}
服务端实现一个查询(Query
)服务,包含一个方法GetAge
。方法GetAge
的入参前加关键字stream
来表明该方法启用客户端流
2.1.2 在.\gRPC-ClientStreaming\pb目录下使用protoc工具进行编译,在pb文件夹下直接生成.pb.go和_grpc.pb.go文件。关于protoc的详细使用可以查看【Golang | gRPC】使用protoc编译.proto文件
protoc --go_out=./ --go-grpc_out=./ .\query.proto
2.2 grpc.pb.go文件
2.2.1 查看query_grpc.pb.go
中生成的客户端流和服务端流的接口定义以及服务端QueryServer
服务的定义
// 客户端流
type Query_GetAgeClient interface {Send(*UserInfo) errorCloseAndRecv() (*AgeInfo, error)grpc.ClientStream
}
// 服务端流
type Query_GetAgeServer interface {SendAndClose(*AgeInfo) errorRecv() (*UserInfo, error)grpc.ServerStream
}
// Query服务的客户端接口
type QueryClient interface {GetAge(ctx context.Context, opts ...grpc.CallOption) (Query_GetAgeClient, error)
}
// Query服务的服务端接口
type QueryServer interface {GetAge(Query_GetAgeServer) errormustEmbedUnimplementedQueryServer()
}
- 客户端流使用
Send
发送message,使用CloseAndRecv
接收message - 客户端
GetAge
方法的第一个返回值是Query_GetAgeClient
,表明生成了一条流,用于发送和接收message;如果有多个方法,则每个方法可以各自生成一条流 - 服务端
GetAge
方法的入参是Query_GetAgeServer
(流),具体方法需要用户自行实现,可以从流中接收和发送message
2.3 服务端
在gRPC-ClientStreaming目录下新建Server文件夹,新建main.go文件
2.3.1 下面我们通过Query这个结构体具体实现QueryServer接口
// 用户信息
var userinfo = map[string]int32{"foo": 18,"bar": 20,
}type Query struct {pb.UnimplementedQueryServer // 涉及版本兼容
}func (q *Query) GetAge(serverStream pb.Query_GetAgeServer) error {log.Println("start of stream")var names_received []*pb.UserInfofor {userinfoRecv, err := serverStream.Recv()// 待客户端主动关闭流后,退出for循环if err == io.EOF {log.Println("end of the recv direction of the stream")break}log.Printf("The name of user received is %s\n", userinfoRecv.GetName())names_received = append(names_received, userinfoRecv)}// 统计年龄和var ages_sum int32for _, v := range names_received {ages_sum += userinfo[v.GetName()]}// 返回messagelog.Printf("send message about the total of ages:%d ", ages_sum)err := serverStream.SendAndClose(&pb.AgeInfo{Age: ages_sum})if err != nil {log.Panic(err)}log.Println("end of the send direction of the stream")return nil
}
- 服务端每收到一个message,保存其用户名,直到客户端关闭发送方向的流
Recv
方法会一直阻塞直到从stream中接收到message,或者直到客户端调用CloseAndRecv
方法- 当客户端调用
CloseAndRecv
方法时,服务端调用Recv
方法会得到io.EOF
返回值 - 服务端调用
SendAndClose
方法发送响应message并关闭发送方向的流
2.3.2 服务注册并启动
func main() {// 创建socket监听器listener, _ := net.Listen("tcp", ":1234")// new一个gRPC服务器,用来注册服务grpcserver := grpc.NewServer()// 注册服务方法pb.RegisterQueryServer(grpcserver, new(Query))// 开启gRPC服务_ = grpcserver.Serve(listener)
}
使用RegisterQueryServer
这个方法向gRPC服务器
里注册QueryServer
2.4 客户端
在gRPC-ClientStreaming目录下新建Client文件夹,新建main.go文件
2.4.1 先建立无认证的连接,生成Client,然后通过方法GetAge
返回对应的流,最后通过流进行message的收发
func main() {//建立无认证的连接conn, err := grpc.Dial(":1234", grpc.WithTransportCredentials(insecure.NewCredentials()))if err != nil {log.Panic(err)}defer conn.Close()client := pb.NewQueryClient(conn)//返回GetAge方法对应的流queryStream, _ := client.GetAge(context.Background())// 向stream中发送message_ = queryStream.Send(&pb.UserInfo{Name: "foo"})time.Sleep(time.Second)_ = queryStream.Send(&pb.UserInfo{Name: "bar"})time.Sleep(time.Second)// 发送两次数据后主动关闭流并等待接收来自server端的messageages_sum, err := queryStream.CloseAndRecv()if err != nil {log.Println(err)}fmt.Printf("The total of ages of foo and bar is %d", ages_sum.GetAge())
}
- 客户端通过
CloseAndRecv
方法主动关闭发送方向的流同时等待接收来自服务端的message
运行结果如下:
3. 总结
- 客户端通过
Send
方法多次发送message,通过CloseAndRecv
方法主动关闭发送方向的流同时等待接收来自服务端的message - 服务端通过
Recv
方法多次接收message,通过SendAndClose
方法发送响应message并关闭发送方向的流
【Golang | gRPC】gRPC-Client Streaming客户端流实战相关推荐
- java版gRPC实战之四:客户端流
欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos <java版gRPC实战>全系列链接 用p ...
- 使用Golang搭建gRPC服务提供给.NetCore客户端调用
gRPC概述 RPC 说到gRPC就不得不提RPC,所谓RPC(remote procedure call 远程过程调用)框架实际是提供了一套机制,使得应用程序之间可以进行通信,简单点来说就是我A机器 ...
- gRPC的通信方式-客户端流式、服务端流式、双向流式在Java的调用示例
场景 gPRC简介以及Java中使用gPRC实现客户端与服务端通信(附代码下载): https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/ ...
- grpc(3):使用 golang 开发 grpc 服务端和client
1,关于grpc-go golang 能够能够做grpc的服务端和client. 官网的文档: http://www.grpc.io/docs/quickstart/go.html https://g ...
- 用Golang构建gRPC服务
本教程提供了Go使用gRPC的基础教程 在教程中你将会学到如何: 在.proto文件中定义一个服务. 使用protocol buffer编译器生成客户端和服务端代码. 使用gRPC的Go API为你的 ...
- Go语学习笔记 - grpc server/client protobuf | 从零开始Go语言
目录 创建Proto文件 生成proto文件对应的go文件 创建服务结构体 创建客户端测试 小结 学习笔记,写到哪是哪. 上一篇是写的redis操作来着,最近主要研究了一下grpc. 在玩grpc的过 ...
- 使用Golang搭建gRPC服务提供给.NetCore调用
文章目录 gRPC概述 RPC gRPC又是什么呢 安装 Golang IDE(Goland) Protocol Buffer 下载Protocal Buffer 配置Protocal Buffer编 ...
- go get google.golang.org/grpc 解决办法汇总
go get -u google.golang.org/grpc 提示网络不通 package google.golang.org/grpc: unrecognized import path &qu ...
- golang安装grpc,timeout问题
官方安装命令: go get google.golang.org/grpc 是安装不起的,会报: package google.golang.org/grpc: unrecognized import ...
最新文章
- 一文看尽 27 篇 CVPR 2021 2D 目标检测论文
- 未分配内存的指针导致段错误
- Receiver ED、Link quality indicator (LQI)、Clear channel assessment (CCA)究竟是什么?802.15.4标准
- 工作53:$router问题
- 华为方舟编译器正式开源,采用自主平台托管
- saltstack event 实践
- ASP.NET页面间的传值的几种方法
- hdu1023-----卡特兰数
- pt100铂电阻型号_铂热电阻型号及铂热电阻接线方法
- MySQL-存储表情字符
- PMU电池管理配置与io-domain电源域
- HTML网页设计期末课程大作业~仿腾讯游戏官网设计与实现(HTML+CSS+JavaScript)
- Vue 可暂停计时器
- Typora Emoji图标
- perl中grep用法总结 z
- 10 Three.js使用orbit controls插件(轨道控制)来控制模型交互动作
- MMPV-上月账期关闭,当月账期打开
- suse linux 单用户,如何在 SUSE 12 Linux 中进入单用户模式?
- SEO站群外链建设批量管理
- 2008最新全套计算机毕业设计