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 代码目录

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()
}

grpc流模式-go实现的更多相关文章

  1. TCP的流模式与UDP的报文模式对比

    1       案例背景 在学习TCP-IP协议详解卷一时,读到介绍TCP协议的部分,发现TCP的首部是没有报文总长度字段的,而在UDP中是有的,对这个问题的思考引出了两者之间的区别. 2    案例 ...

  2. TCP 流模式与UDP数据报模式(转)

    TCP流模式与UDP数据报模式http://blog.csdn.net/s3olo/article/details/7914717 数据报(datagram)通常是指起始点和目的地都使用无连接网络服务 ...

  3. RecyclerView实例-实现可下拉刷新上拉加载更多并可切换线性流和瀑布流模式(1)

    摘要 最近项目有个列表页需要实现线性列表和瀑布流展示的切换,首先我想到的就是上 [RecyclerView],他本身已经很好的提供了三种布局方式,只是简单做个切换应该是很简单的事情,如果要用Recyc ...

  4. kcp流模式与消息模式对比

    kcp的流模式,和消息模式 流模式: 更高的网络利用率 更大的传输速度 解析数据相对更复杂 消息模式: 更小的网络利用率 更小的传输速度 解析数据相对更简单 消息模式的示意图 http://www.p ...

  5. grpc Unary模式下客户端创建insecure channel的主要流程

    (原创)C/C/1.25.0-dev grpc-c/8.0.0, 使用的例子是自带的例子GreeterClient grpc Unary模式下客户端创建insecure channel的主要流程 gr ...

  6. WAFの基本防护透明流模式v1.0

                      一.WAFの透明流模式     1)首先先配置WAF的网络,配置一个网桥接口,设置IP便于带内管理.             2)当然,如果需要不同网段之间都能够管 ...

  7. 流量治理神器-Sentinel的限流模式,选单机还是集群?

    大家好,架构摆渡人.这是我的第5篇原创文章,还请多多支持. 上篇文章给大家推荐了一些限流的框架,如果说硬要我推荐一款,我会推荐Sentinel,Sentinel的限流模式分为两种,分别是单机模式和集群 ...

  8. 容量测试之tcpcopy引流模式

    tcpcopy 给用户提供了很多命令参数来修改引流的模式和设置,详细可以查阅手册.在这里把几种常见的引流方式做个归纳小结,以tcpcopy传统架构使用命令举例. 1.分布式引流 用法:Tcpcopy可 ...

  9. IE文档版本和文档流模式

    使用X-UA-Compatible来设置IE浏览器兼容模式 文件兼容性用于定义让IE如何编译你的网页.此文件解释文件兼容性,如何指定你网站的文件兼容性模式以及如何判断一个网页该使用的文件模式. < ...

随机推荐

  1. Java基础——ArrayList

    Java基础--ArrayList 作用:提供一个可变长度的集合,底层实际上是一个可变长度的数组 格式:ArrayList <E> arr=new ArrayList<>(); ...

  2. python3输出由1、2、3、4这四个数字组成的每位数都不相同的所有三位数

    for i in range(1,5): for j in range(1,5): for k in range(1,5): if(i!=j and i!=k and j!=k): print(i*1 ...

  3. bat加mimikatz一键获取密码

    1 @echo off 2 >nul 2>&1 "%SYSTEMROOT%\system32\cacls.exe" "%SYSTEMROOT%\sys ...

  4. 07模块化设计之top_down

    一设计功能:(一)用两个分频模块,实现16分频,且让输入a 和b在16个系统时钟内,相与一次. (二)模块化设计思想(结构化思维) 拆分,即把一个系统划分成多个功能模块,控制模块,组合模块.然后从功能 ...

  5. C/C++ 文件读写

    •前言 第一次接触文件读写是在大一的C语言教材中,当时哼哧吧唧的学的贼费劲,虽然最后也学会了,但好像没怎么用过. 在后来,就是在OJ上刷题的时候,编写的代码有时候连样例都不能通过: 这个时候就需要各种 ...

  6. 羽夏看Win系统内核——消息机制篇

    写在前面   此系列是本人一个字一个字码出来的,包括示例和实验截图.由于系统内核的复杂性,故可能有错误或者不全面的地方,如有错误,欢迎批评指正,本教程将会长期更新. 如有好的建议,欢迎反馈.码字不易, ...

  7. 机械学习笔记1 -> Solidworks三维产品设计与建模1 | 建模基础入门

    学习之余,课余了解一点点,作为爱好,妄想以后能够设计机甲出来. 学习来源是Solidworks三维产品设计与建模 00 工作界面介绍 00-1 概览 有时菜单栏和工具栏会重叠在一起,只有点击左侧三角才 ...

  8. 火花思维java

    面试过程: 问的问题比较广,涉及java基础与互联网中间件,数据库很多知识,面试官态度非常友好,对于错的回答也做出来相应解答 面试官问的面试题: 1.redis如何保证数据一致性2.mysql的索引机 ...

  9. 设置一段文字的大小为6px?

    谷歌最小12px, 其他浏览器可以更小 通过transform: scale实现

  10. springboot-@EventListener简单用法

    @EventListener简单描述 简化我们编写监听类的步骤,不需要再继承ApplicationListener接口去实现onApplicationEvent了. 例子: @Component pu ...