gRPC之流模式

本文介绍了gRPC中服务端流模式与普通模式的区别,并提供了示例代码进行说明。在服务端流模式下,服务器可以分批发送响应,而普通模式则一次性返回所有数据。通过对比两种模式的实现,展示了如何在服务端控制数据发送频率和客户端如何处理接收到的数据流。
摘要由CSDN通过智能技术生成

服务端流

在这里插入图片描述
业务场景:用户积分

  1. .proto代码
// 用户积分模块
message UserInfo{
  int32 user_id=1;
  int32 user_score=2;
}
message UserScoreRequest{
  repeated UserInfo users = 1;
}
message UserScoreResponse{
  repeated UserInfo users =1;
}
service UserService{
  rpc GetUserScore(UserScoreRequest) returns(UserScoreResponse);
  rpc GetUserScoreByServerStream(UserScoreRequest) returns(stream UserScoreResponse);
}
  1. 生成protoc --go_out=…/services Product.proto protoc --go–grpc_out=…/services Product.proto
  2. 普通模式与s流模式对比 service.go代码:
// 服务端流模式 CS传输
func (s *UserService) GetUserScoreByServerStream(request *UserScoreRequest, stream UserService_GetUserScoreByServerStreamServer) error {
	var score int32 = 101
	users := make([]*UserInfo, 0)
	for index, user := range request.Users {
		user.UserScore = score
		score++
		users = append(users, user)
		// 数据库协程
		if (index+1)%2 == 0 && index > 0 { // 每隔两条发送
			err := stream.Send(&UserScoreResponse{Users: users})
			if err != nil {
				return err
			}
			users = (users)[0:0] // 空切片
		}
		time.Sleep(time.Second*1) // 这里每一秒发送一些数据
	}
	if len(users)>0{
		err2 := stream.Send(&UserScoreResponse{Users: users})
		if err2!=nil{
			return err2
		}
	}
	return nil
}

// 普通模式 CS传输
func (s *UserService) GetUserScore(ctx context.Context, request *UserScoreRequest) (*UserScoreResponse, error) {
	var score int32 = 101
	users := make([]*UserInfo, 0)
	for _, user := range request.Users {
		user.UserScore = score
		score++
		users = append(users, user)
		time.Sleep(time.Second*1) // 这里每5秒才发送全部数据
	}
	return &UserScoreResponse{Users: users}, nil
}
  1. server.go
func main(){
	cert, _ := tls.LoadX509KeyPair("cert/server.pem", "cert/server.key")
	certPool := x509.NewCertPool()
	ca, _ := ioutil.ReadFile("cert/ca.pem")
	certPool.AppendCertsFromPEM(ca)

	creds := credentials.NewTLS(&tls.Config{
		Certificates: []tls.Certificate{cert}, // 服务端证书
		ClientAuth:   tls.RequireAndVerifyClientCert, // 双向验证
		ClientCAs:    certPool,
	})

	rpcServer := grpc.NewServer(grpc.Creds(creds)) // 传入证书
	//rpcServer := grpc.NewServer() // 传入证书
	services.RegisterProdServiceServer(rpcServer,new(services.ProdService)) // 注册商品服务
	services.RegisterOrderServiceServer(rpcServer,new(services.OrderService)) // 注册订单服务
	services.RegisterUserServiceServer(rpcServer,new(services.UserService)) // 用户积分服务
	lis, _ := net.Listen("tcp", ":8081")
	rpcServer.Serve(lis)
}
  1. client.go
// 用户积分模块,普通模式
	userClient := NewUserServiceClient(conn)

	var i int32
	req := UserScoreRequest{}
	req.Users=make([]*UserInfo,0)
	for i = 1; i < 6; i++ {
		req.Users=append(req.Users,&UserInfo{
			UserId: i,
		})
	}
	resUserSocre, _ := userClient.GetUserScore(context.Background(), &req)
	fmt.Println(resUserSocre.Users)
	// 用户积分模块2,客户端流模式
	userClient2 := NewUserServiceClient(conn)

	var i2 int32
	req2 := UserScoreRequest{}
	req2.Users=make([]*UserInfo,0)
	for i2 = 1; i2 < 6; i2++ {
		req2.Users=append(req2.Users,&UserInfo{
			UserId: i2,
		})
	}
	stream, err := userClient2.GetUserScoreByServerStream(context.Background(), &req2)
	if err != nil {
		log.Fatal(err)
	}
	for{ // 循环读流
		recv, err := stream.Recv()
		if err==io.EOF { // 当发送完数据时
			break
		}
		if err!=nil{
			log.Fatal(err)
		}
		fmt.Println(recv.Users) // 当获取到一条数据时,立即开协程去处理.实现一边接受,一边处理
	}

客户端流

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值