上一篇我们写了普通的grpc的调用过程,这篇接上篇写一下客户端流式 grpc
目录结构
protofile 目录是proto文件与生成go代码的命令proto.bat
product.proto
syntax = "proto3"; //protobuf的版本
option go_package="../service";
package service; //指定生成出来的 package
//定义request model
message ProductRequest{
int32 prod_id = 1;
}
//定义response model
message ProductResponse{
int32 prod_socket = 1;
}
service ProdService{
//客户端流式传入
rpc GetProdSocketSteamClient(stream ProductRequest)returns(ProductResponse);
}
proto.bat 命令
protoc --go_out=./ --go-grpc_out=./ .\product.proto
server目录写的是服务端接受客户端流式的业务逻辑
package main
import (
"grpc-client-stream/service"
"io"
"log"
"net"
"google.golang.org/grpc"
)
type ProductService struct {
*service.UnimplementedProdServiceServer
}
var productService = ProductService{}
/***********
接客户端流式发送的数据id 返回len后的id个数
服务端每收到一个message,保存其发送的ID,直到客户端关闭发送方向的流
Recv方法会一直阻塞直到从stream中接收到message,或者直到客户端调用CloseAndRecv方法
当客户端调用CloseAndRecv方法时,服务端调用Recv方法会得到io.EOF返回值
服务端调用SendAndClose方法发送响应message并关闭发送方向的流
***/
func (p ProductService) GetProdSocketSteamClient(stream service.ProdService_GetProdSocketSteamClientServer) error {
log.Println("start of stream")
var productRequest []*service.ProductRequest //切片准备
//for循环开始接
for {
//接到的数据
recv, err := stream.Recv()
//数据接完了就跳出循环
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", recv.GetProdId())
//将接到的数据塞到切片中
productRequest = append(productRequest, recv)
}
//计算切片长度 并把int类型转化为int32
i := int32(len(productRequest))
log.Printf("send message about the prodIDSocket:%d ", i)
//关闭结束
err := stream.SendAndClose(&service.ProductResponse{ProdSocket: i})
if err != nil {
log.Panic(err)
}
log.Println("end of the send direction of the stream")
return nil
}
func main() {
// 创建socket监听器
listener, _ := net.Listen("tcp", ":1234")
// new一个gRPC服务器,用来注册服务
grpcserver := grpc.NewServer()
// 注册服务方法
service.RegisterProdServiceServer(grpcserver, productService)
// 开启gRPC服务
_ = grpcserver.Serve(listener)
}
client目录是客户端向服务端流式发送并接受服务端的返回信息
package main
import (
"context"
"fmt"
"grpc-client-stream/service"
"log"
"time"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
)
func main() {
//建立无认证链接
dial, err := grpc.Dial(":1234", grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
log.Fatal(err.Error())
}
defer dial.Close()
//客户端实例化链接
client := service.NewProdServiceClient(dial)
//调用服务端方法
steam, err := client.GetProdSocketSteamClient(context.Background())
if err != nil {
log.Fatal(err.Error())
}
for i := 0; i < 10; i++ {
//向服务端发送流信息
_ = steam.Send(&service.ProductRequest{ProdId: int32(i)})
//等1秒
time.Sleep(time.Second)
}
// 发送两次数据后主动关闭流并等待接收来自server端的message
recv, err := steam.CloseAndRecv()
if err != nil {
log.Println(err)
}
fmt.Printf("The total is %d", recv.GetProdSocket())
}
service目录是protobuf生成的文件
打开服务端的mian服务,再打开个命令行窗口打开客户端的main 进行请求就可以了
粗浅的理解,如果有什么不对的地方 请多多指教