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 相关文章推荐
对Golang中的FORM相关字段理解
May 02 Golang
golang协程池模拟实现群发邮件功能
May 02 Golang
golang 定时任务方面time.Sleep和time.Tick的优劣对比分析
May 05 Golang
Golang之sync.Pool使用详解
May 06 Golang
Go 自定义package包设置与导入操作
May 06 Golang
Go 在 MongoDB 中常用查询与修改的操作
May 07 Golang
Go语言实现Base64、Base58编码与解码
Jul 26 Golang
使用GO语言实现Mysql数据库CURD的简单示例
Aug 07 Golang
golang实现一个简单的websocket聊天室功能
Oct 05 Golang
golang使用map实现去除重复数组
Apr 14 Golang
Golang 入门 之url 包
May 04 Golang
Go语言测试库testify使用学习
Jul 23 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制作静态网站的模板框架(二)
2006/10/09 PHP
Yii快速入门经典教程
2015/12/28 PHP
PHP合并数组函数array_merge用法分析
2017/02/17 PHP
php数组指针函数功能及用法示例
2020/02/11 PHP
formvalidator验证插件中有关ajax验证问题
2013/01/04 Javascript
原始的js代码和jquery对比体会
2013/09/10 Javascript
jquery实现百叶窗效果
2017/01/12 Javascript
vue模板语法-插值详解
2017/03/06 Javascript
AngularJS实现页面定时刷新
2017/03/14 Javascript
JavaScript中防止微信浏览器被整体拖动的方法
2017/08/25 Javascript
讲解vue-router之什么是编程式路由
2018/05/28 Javascript
Vue.js 中取得后台原生HTML字符串 原样显示问题的解决方法
2018/06/10 Javascript
小程序开发基础之view视图容器
2018/08/21 Javascript
vue+element tabs选项卡分页效果
2020/06/29 Javascript
react quill中图片上传由默认转成base64改成上传到服务器的方法
2019/10/30 Javascript
基于vue-simple-uploader封装文件分片上传、秒传及断点续传的全局上传插件功能
2021/02/23 Vue.js
[43:41]VP vs RNG 2019国际邀请赛淘汰赛 败者组 BO3 第二场 8.21.mp4
2020/07/19 DOTA
[01:11:21]DOTA2-DPC中国联赛 正赛 Phoenix vs CDEC BO3 第三场 3月7日
2021/03/11 DOTA
python 正则表达式 概述及常用字符
2009/05/04 Python
Python 描述符(Descriptor)入门
2016/11/20 Python
对python3标准库httpclient的使用详解
2018/12/18 Python
python爬虫 正则表达式解析
2019/09/28 Python
python实现二分类的卡方分箱示例
2019/11/22 Python
在pycharm中创建django项目的示例代码
2020/05/28 Python
html5简单示例_动力节点Java学院整理
2017/07/07 HTML / CSS
大专毕业生自我鉴定
2013/11/21 职场文书
2013的个人自我评价
2013/12/26 职场文书
2014离婚协议书范文(3篇)
2014/11/29 职场文书
2014年政协工作总结
2014/12/09 职场文书
2014年学校办公室工作总结
2014/12/19 职场文书
2015年五四青年节演讲稿
2015/03/18 职场文书
志愿者服务活动总结报告
2015/05/06 职场文书
李强为自己工作观后感
2015/06/11 职场文书
在校生证明
2015/06/17 职场文书
Python Flask搭建yolov3目标检测系统详解流程
2021/11/07 Python
JS轻量级函数式编程实现XDM三
2022/06/16 Javascript