grpc---双向流式

本文继续上一篇关于服务端流式gRPC的内容,重点介绍如何实现双向流式gRPC。文章通过`product.proto`定义服务,并使用`proto.bat`命令生成Go代码。在server目录中,展示了服务端的流式业务逻辑,而在client目录,则详细说明了客户端如何接收并处理服务端流式返回的信息。

上一篇我们写了服务端端流式的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())
	}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值