grpc流模式的实例

grpc流模式的实例

grpc中的stream,srteam顾名思义就是一种流,可以源源不断的推送数据,或者服务端和客户端长时间数据交互。

grpc的四种数据流

  1. 简单模式 : 即客户端发起一次请求,服务端响应一个数据; 在proto3中不用指定 stream。
  2. 服务端数据流模式: 这种模式是客户端发起一次请求,服务端返回一段连续的数据流。在proto3中如 rpc ServerMod (RequestData) returns (stream ResponseData);
  3. 客户端数据流模式: 与服务端数据流模式相反,这次是客户端源源不断的向服务端发送数据流,而在发送结束后,由服务端返回一个响应。在proto3中如 rpc ClientMod (stream RequestData) returns (ResponseData);
  4. 双向数据流: 客户端和服务端都可以向对方发送数据流,这个时候双方的数据可以同时互相发送,也就是可以实现实时交互。 在proto3中如 rpc AllMod (stream RequestData) returns (stream ResponseData);

本次实例用的 proto3

syntax = "proto3";

option go_package = "./;pb";

service Mod {
    rpc ServerMod (RequestData) returns (stream ResponseData);      //服务端流模式,拉消息
    rpc ClientMod (stream RequestData) returns (ResponseData);      //客户端流模式,推消息
    rpc AllMod (stream RequestData) returns (stream ResponseData);  //双向流模式,能推能拉
}

message RequestData {
    string data = 1;
}

message ResponseData {
    string data = 1;
}

Server端实现

const port = 8082

type server struct{}

// 服务端流模式,拉消息
func (s *server) ServerMod(req *pb.RequestData, res pb.Mod_ServerModServer) error {
	i := 0
	for {
		i++
		//业务代码
		_ = res.Send(&pb.ResponseData{
			Data: fmt.Sprintf("这是发给%s的数据流", req.Data),
		})
		time.Sleep(time.Second * 1)
		if i > 10 {
			break
		}
	}
	return nil
}

// 客户端流模式,推消息
func (s *server) ClientMod(cliStr pb.Mod_ClientModServer) error {
	for {
		//业务代码
		res, err := cliStr.Recv()
		if err != nil {
			fmt.Println("本次客户端流数据发送完了:",err)
			break
		}
		fmt.Println("客户端发来消息:",res.Data)
	}
	return nil
}

// 双向流模式,能推能拉
func (s *server) AllMod(allStr pb.Mod_AllModServer) error {
	wg:=sync.WaitGroup{}
	wg.Add(2)
	//接受客户端消息的协程
	go func() {
		defer wg.Done()
		for  {
			//业务代码
			res, err := allStr.Recv()
			if err != nil {
				fmt.Println("本次客户端流数据发送完了:",err)
				break
			}
			fmt.Println("收到客户端发来消息:",res.Data)
		}
	}()

	//发送消息给客户端的协程
	go func() {
		defer wg.Done()
		i := 0
		for {
			i++
			//业务代码
			_ = allStr.Send(&pb.ResponseData{
				Data: fmt.Sprintf("这是发给客户端的数据流"),
			})
			time.Sleep(time.Second * 1)
			if i > 10 {
				break
			}
		}
	}()
	wg.Wait()
	return nil
}

// 启动
func start() {
	// 1.实例化server
	g := grpc.NewServer()
	// 2.注册逻辑到server中
	pb.RegisterModServer(g, &server{})
	// 3.启动server
	lis, err := net.Listen("tcp", "127.0.0.1:8082")
	if err != nil {
		panic("监听错误:" + err.Error())
	}
	err = g.Serve(lis)
	if err != nil {
		panic("启动错误:" + err.Error())
	}

}

func main() {
	start()
}

Client端实现

package main

import (
	"context"
	"fmt"
	"go_script/grpc_3/pb"
	"google.golang.org/grpc"
	"sync"
	"time"
)

var rpc pb.ModClient

// 服务端流模式
func serverStreamDemo()  {
	res,err:=rpc.ServerMod(context.Background(),&pb.RequestData{Data: "服务端流模式"})
	if err != nil {
		panic("rpc请求错误:"+err.Error())
	}
	for  {
		data,err:=res.Recv() //
		if err != nil {
			fmt.Println("客户端发送完了:",err)
			return
		}
		fmt.Println("客户端返回数据流值:",data.Data)
	}
}

// 客户端流模式
func clientStreamDemo()  {
	cliStr, err := rpc.ClientMod(context.Background())
	if err != nil {
		panic("rpc请求错误:" + err.Error())
	}
	i := 0
	for {
		i++
		_ = cliStr.Send(&pb.RequestData{
			Data: "客户端流模式",
		})
		time.Sleep(time.Second * 1)
		if i > 10 {
			break
		}
	}
}

// 双向流模式
func clientAndServerStreamDemo()  {
	allStr, _ := rpc.AllMod(context.Background())
	wg := sync.WaitGroup{}
	wg.Add(1)

	//接受服务端消息的协程
	go func() {
		defer wg.Done()
		for {
			//业务代码
			res, err := allStr.Recv()
			if err != nil {
				fmt.Println("本次服务端流数据发送完了:", err)
				break
			}
			fmt.Println("收到服务端发来消息:", res.Data)
		}
	}()

	//发送消息给服务端的协程
	go func() {
		defer wg.Done()
		i := 0
		for {
			i++
			//业务代码
			_ = allStr.Send(&pb.RequestData{
				Data: fmt.Sprintf("这是发给服务端的数据流"),
			})
			time.Sleep(time.Second * 1)
			if i > 10 {
				break
			}
		}
	}()
	wg.Wait()
}

// 启动
func start() {
	conn, err := grpc.Dial("127.0.0.1:8082", grpc.WithInsecure())
	if err != nil {
		panic("rpc连接错误:" + err.Error())
	}
	defer conn.Close()
	rpc = pb.NewModClient(conn) //初始化

	serverStreamDemo() //服务端流模式

	clientStreamDemo()  //客户端流模式

	clientAndServerStreamDemo() // 双向流模式
}

func main() {
	start()
}

最后

可以在实际业务中灵活使用,根据漫哥的经验可以按照需求进行设计数据在各个子服务中的流向;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值