Golang流模式之grpc的四种数据流


Posted in Golang onApril 13, 2022

1. 什么是数据流

grpc中的stream,srteam顾名思义就是一种流,可以源源不断的推送数据,很适合传输一些大数据,或者服务端和客户端长时间数据交互,比如客户端可以向服务端订阅一个数据,服务端就可以利用stream,源源不断地推送数据。

底层还原成socket编程

2. grpc的四种数据流

1.简单模式
2.服务端数据流模式(Server-side streaming RPC)
3.客户端数据流模式(Client-side streaming RPC)
4.双向数据流模式(Bidirectional streaming RPC)

2.1 简单模式

这种模式最为传统,即客户端发起一次请求,服务端响应一个数据,这和大家平时熟悉的RPC没有什么大的区别,上两篇中介绍此模式。

2.2 服务端数据流模式

这种模式是客户端发起一次请求,服务端返回一段连续的数据流。典型的例子是客户端向服务端发送一个股票代码,服务端就把该股票的实时数据源源不断的返回给客户端

2.3 客户端数据流模式

与服务端数据流模式相反,这次是客户端源源不断的向服务端发送数据流,而在发送结束后,由服务端返回一个响应。典型的例子是物联网终端向服务器报送数据。

2.4 双向数据流

顾名思义,这是客户端和服务端都可以向对方发送数据流,这个时候双方的数据可以同时互相发送,也就是可以实现实时交互。典型的例子是聊天机器人。

3. 上代码

3.1 代码目录

Golang流模式之grpc的四种数据流

3.2 编写stream.proto文件

stream是常量,写在哪一边,哪一边就是数据流
syntax = "proto3";

option go_package = "./;proto";

service Greeter {
    // 定义方法,stream是常量,流模式
    rpc ServerStream (StreamRequestData) returns (stream StreamResponseData);      //服务端流模式,拉消息
    rpc ClientStream (stream StreamRequestData) returns (StreamResponseData);      //客户端流模式,推消息
    rpc AllStream (stream StreamRequestData) returns (stream StreamResponseData);  //双向流模式,能推能拉
}

message StreamRequestData {
    string data = 1; //编号
}

message StreamResponseData {
    string data = 1; //编号
}
生成go的protobuf文件命令:
cd到proto目录下
命令:protoc -I . hello.proto   --go_out=plugins=grpc:.

3.3 编写server文件

package main

import (
	"file_test/grpc_go_stream/proto"
	"fmt"
	"net"
	"sync"
	"time"

	"google.golang.org/grpc"
)

const port = 8082

type server struct{}

func (s *server) ServerStream(req *proto.StreamRequestData, res proto.Greeter_ServerStreamServer) error {
	i := 0
	for {
		i++
		//业务代码
		_ = res.Send(&proto.StreamResponseData{
			Data: fmt.Sprintf("这是发给%s的数据流", req.Data),
		})
		time.Sleep(time.Second * 1)
		if i > 10 {
			break
		}
	}
	return nil
}
func (s *server) ClientStream(cliStr proto.Greeter_ClientStreamServer) error {
	for {
		//业务代码
		res, err := cliStr.Recv()
		if err != nil {
			fmt.Println("本次客户端流数据发送完了:",err)
			break
		}
		fmt.Println("客户端发来消息:",res.Data)
	}
	return nil
}
func (s *server) AllStream(allStr proto.Greeter_AllStreamServer) 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(&proto.StreamResponseData{
				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中
	proto.RegisterGreeterServer(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()
}

3.4 编写client文件

package main

import (
	"context"
	"file_test/grpc_go_stream/proto"
	"fmt"
	"sync"
	"time"

	"google.golang.org/grpc"
)

var rpc proto.GreeterClient

func serverStreamDemo()  {
	//服务端流模式
	res,err:=rpc.ServerStream(context.Background(),&proto.StreamRequestData{Data: "jeff"})
	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.ClientStream(context.Background())
	if err != nil {
		panic("rpc请求错误:" + err.Error())
	}
	i := 0
	for {
		i++
		_ = cliStr.Send(&proto.StreamRequestData{
			Data: "jeff",
		})
		time.Sleep(time.Second * 1)
		if i > 10 {
			break
		}
	}
}

func clientAndServerStreamDemo()  {
	//双向流模式
	allStr, _ := rpc.AllStream(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(&proto.StreamRequestData{
				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 = proto.NewGreeterClient(conn) //初始化

	serverStreamDemo() //服务端流模式

	clientStreamDemo()  //客户端流模式

	clientAndServerStreamDemo() // 双向流模式
}

func main() {
	start()
}

以上就是go实现grpc四种数据流模式的详细内容!

Golang 相关文章推荐
win10下go mod配置方式
Apr 25 Golang
Go语言带缓冲的通道实现
Apr 26 Golang
golang gopm get -g -v 无法获取第三方库的解决方案
May 05 Golang
go使用Gin框架利用阿里云实现短信验证码功能
Aug 04 Golang
golang 语言中错误处理机制
Aug 30 Golang
golang为什么要统一错误处理
Apr 03 Golang
Go归并排序算法的实现方法
Apr 06 Golang
Golang 字符串的常见操作
Apr 19 Golang
Golang bufio详细讲解
Apr 21 Golang
详解Go语言中Get/Post请求测试
Jun 01 Golang
Go调用Rust方法及外部函数接口前置
Jun 14 Golang
Go语言怎么使用变长参数函数
Jul 15 Golang
Golang数据类型和相互转换
Apr 12 #Golang
Go语言的协程上下文的几个方法和用法
Apr 11 #Golang
Golang 1.18 多模块Multi-Module工作区模式的新特性
Apr 11 #Golang
golang三种设计模式之简单工厂、方法工厂和抽象工厂
Golang原生rpc(rpc服务端源码解读)
Apr 07 #Golang
Go并发4种方法简明讲解
Go归并排序算法的实现方法
Apr 06 #Golang
You might like
PHP 读取文件的正确方法
2009/04/29 PHP
PHP采集利器 Snoopy 试用心得
2011/07/03 PHP
php数组函数序列之array_search()- 按元素值返回键名
2011/11/04 PHP
php读取文件内容的几种方法详解
2013/06/26 PHP
PHP反射基础知识回顾
2020/09/10 PHP
jquery 输入框数字限制插件
2009/11/10 Javascript
使用ImageMagick进行图片缩放、合成与裁剪(js+python)
2013/09/16 Javascript
JS实现将人民币金额转换为大写的示例代码
2014/02/13 Javascript
jquery制作select列表双向选择示例代码
2014/09/02 Javascript
Javascript实现的Map集合工具类完整实例
2015/07/31 Javascript
jQuery解析json数据实例分析
2015/11/24 Javascript
jquery获取复选框checkbox的值的简单实现方法
2016/05/26 Javascript
HTML页面定时跳转方法解析(2种任选)
2016/12/22 Javascript
一个例子轻松学会Vue.js
2017/01/02 Javascript
Angular中使用$watch监听object属性值的变化(详解)
2017/04/24 Javascript
JS实现批量上传文件并显示进度功能
2017/06/27 Javascript
layer.open 按钮的点击事件关闭方法
2018/08/17 Javascript
分享Python字符串关键点
2015/12/13 Python
一篇文章读懂Python赋值与拷贝
2018/04/19 Python
python2与python3的print及字符串格式化小结
2018/11/30 Python
一篇文章搞定Python操作文件与目录
2019/08/13 Python
python将字典列表导出为Excel文件的方法
2019/09/02 Python
PyTorch学习:动态图和静态图的例子
2020/01/06 Python
django 扩展user用户字段inlines方式
2020/03/30 Python
django教程如何自学
2020/07/31 Python
适合各种场合的美食礼品:Harry & David
2016/08/03 全球购物
介绍下Java的输入输出流
2014/01/22 面试题
事业单位辞职信范文
2014/01/19 职场文书
人事部经理岗位职责
2014/03/07 职场文书
老师对学生的寄语
2014/04/09 职场文书
领导班子四风问题对照检查材料
2014/09/27 职场文书
环境卫生标语
2015/08/03 职场文书
2016大学生党校学习心得体会
2016/01/06 职场文书
怎样做好公众演讲能力?
2019/08/28 职场文书
Golang中interface{}转为数组的操作
2021/04/30 Golang
vue3获取当前路由地址
2022/02/18 Vue.js