上一篇我们写了服务端端流式的grpc的调用过程,这篇接上篇写一下双向流式 grpc
目录

protofile 目录是proto文件与生成go代码的命令proto.bat
product.proto
syntax = "proto3";
option go_package = "../service";
package service;
message ProductRequest{
int32 prod_id = 1;
}
message ProductResponse{
int32 prod_socket = 1;
}
//定义服务
service ProdService{
//双向流
rpc GetProdSocket(stream ProductRequest)returns(stream ProductResponse);
}
proto.bat 命令
protoc --go_out=./ --go-grpc_out=./ .\product.proto
业务逻辑
server目录写的是服务端流式的业务逻辑
package main
import (
"google.golang.org/grpc"
"grpc-stream/service"
"io"
"log"
"net"
)
type ProductService struct {
*service.UnimplementedProdServiceServer
}
var productService = ProductService{}
func (p ProductService) GetProdSocket(stream service.ProdService_GetProdSocketServer) error {
log.Println("start of stream")
for{
//接收客户端的流
recv, err := stream.Recv()
if err ==io.EOF{
log.Println("客户端流接收完毕,跳出循环")
break
}
//打印客户端的流
log.Printf("接收到客户端的流 %s", recv.GetProdId())
////服务端接收的值打印
//log.Printf("The prodid is %s", recv.GetProdId())
//向客户端发送流 (+100 表示服务端逻辑 对值进行处理后返回)
err = stream.Send(&service.ProductResponse{ProdSocket: recv.ProdId+100})
if err != nil {
log.Fatal(err.Error())
}
}
return nil
}
func main() {
//开启grpc服务
grpcserver := grpc.NewServer()
//将实现注册进去
service.RegisterProdServiceServer(grpcserver,productService)
listen, _ := net.Listen("tcp", ":1234")
//监听端口
grpcserver.Serve(listen)
}
client目录是客户端接收服务端流式发送的返回信息
package main
import (
"context"
"fmt"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
"grpc-stream/service"
"io"
"log"
"time"
)
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)
//调用服务端的方法
stream, _ := client.GetProdSocket(context.Background())
// 创建goroutine用来向stream中发送message
ch := make(chan int32, 5)
go func() {
prodID := []int32{1,2,3,4,5}
for _,v:=range prodID{
log.Printf("客户端发送给服务端的prodid %d\n", v)
ch<-v
//发送流到服务端
_ = stream.Send(&service.ProductRequest{ProdId: v})
time.Sleep(time.Second)
}
// 调用指定次数后主动关闭流
err = stream.CloseSend()
if err != nil {
log.Println(err.Error())
}
fmt.Println("客户端结束发送")
close(ch)
}()
// 从stream中接收message
for {
prodIDResult,ok := <-ch
if ok ==false{
log.Println("在通道里取完了数据")
break
}
prodSocket, err := stream.Recv()
if err == io.EOF {
log.Println("客户端结束接收,跳出循环")
break
}
log.Printf("客户端发送的值是%d,服务端处理过的值%s \n",prodIDResult, prodSocket.GetProdSocket())
}
}
本文继续上一篇关于服务端流式gRPC的内容,重点介绍如何实现双向流式gRPC。文章通过`product.proto`定义服务,并使用`proto.bat`命令生成Go代码。在server目录中,展示了服务端的流式业务逻辑,而在client目录,则详细说明了客户端如何接收并处理服务端流式返回的信息。

1389

被折叠的 条评论
为什么被折叠?



