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 正则匹配效率详解
Apr 25 Golang
解决Golang中ResponseWriter的一个坑
Apr 27 Golang
golang 实现Location跳转方式
May 02 Golang
解决Golang中goroutine执行速度的问题
May 02 Golang
go mod 安装依赖 unkown revision问题的解决方案
May 06 Golang
一文搞懂Golang 时间和日期相关函数
Dec 06 Golang
Go 中的空白标识符下划线
Mar 25 Golang
Go归并排序算法的实现方法
Apr 06 Golang
Golang 切片(Slice)实现增删改查
Apr 22 Golang
Golang并发工具Singleflight
May 06 Golang
go goth封装第三方认证库示例详解
Aug 14 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
全国FM电台频率大全 - 15 山东省
2020/03/11 无线电
利用php来自动调用不同服务器上的flash
2006/10/09 PHP
php类中private属性继承问题分析
2012/11/01 PHP
php动态绑定变量的用法
2015/06/16 PHP
javascrpt绑定事件之匿名函数无法解除绑定问题
2012/12/06 Javascript
jquery Mobile入门—多页面切换示例学习
2013/01/08 Javascript
扩展js对象数组的OrderByAsc和OrderByDesc方法实现思路
2013/05/17 Javascript
js 文本滚动效果的实例代码
2013/08/17 Javascript
可自定义速度的js图片无缝滚动示例分享
2014/01/20 Javascript
Jquery技巧(必须掌握)
2016/03/16 Javascript
jQuery DataTables插件自定义Ajax分页实例解析
2020/04/28 Javascript
Javascript的比较汇总
2016/07/25 Javascript
Node.js的基本知识简单汇总
2016/09/19 Javascript
原生js实现图片放大缩小计时器效果
2017/01/20 Javascript
jquery在vue脚手架中的使用方式示例
2017/08/29 jQuery
JS小球抛物线轨迹运动的两种实现方法详解
2017/12/20 Javascript
vuex实现及简略解析(小结)
2019/03/01 Javascript
WebGL学习教程之Three.js学习笔记(第一篇)
2019/04/25 Javascript
JavaScript实现左右滚动电影画布
2020/02/06 Javascript
详解JS函数防抖
2020/06/05 Javascript
JS实现多选框的操作
2020/06/24 Javascript
vue 使用post/get 下载导出文件操作
2020/08/07 Javascript
[36:22]VP vs Serenity 2018国际邀请赛小组赛BO2 第一场 8.16
2018/08/17 DOTA
django 创建过滤器的实例详解
2017/08/14 Python
在python中使用xlrd获取合并单元格的方法
2018/12/26 Python
Python函数和模块的使用总结
2019/05/20 Python
Python打包模块wheel的使用方法与将python包发布到PyPI的方法详解
2020/02/12 Python
浅析python标准库中的glob
2020/03/13 Python
Python基于numpy模块实现回归预测
2020/05/14 Python
python脚本和网页有何区别
2020/07/02 Python
基于HTML5+CSS3实现简单的时钟效果
2017/09/11 HTML / CSS
新浪网技术部笔试题
2016/08/26 面试题
数据管理员的自我评价分享
2013/11/15 职场文书
20年同学聚会邀请函
2014/02/04 职场文书
什么是就业协议书
2014/04/17 职场文书
导游词之藏龙百瀑景区
2019/12/30 职场文书