go的grpc的三种流模式通信

go的grpc的三种流模式通信

    • 1、grpc通信模式简介
    • 2、stream.proto文件
    • 3、服务端代码 server.go
    • 4、客户端代码client.go
    • 5、测试说明

1、grpc通信模式简介

grpc的数据传输可以分为4种模式:
简单模式 (一元调用)
服务端流模式 (服务端返回实时股票数据给前台)
客户端流模式 (物联网硬件设备向后端发送数据)
双向流模式 (聊天场景)

2、stream.proto文件

syntax = "proto3";

option go_package = "./;proto";

// grpc的数据传输可以分为4种模式:
// 简单模式(一元调用)、服务端流模式(服务端返回实时股票数据给前台)、客户端流模式(物联网硬件设备向后端发送数据)、双向流模式(聊天场景)

service Greeter {
  rpc GetStream(StreamReqData) returns (stream StreamResData);//  服务端流模式
  rpc PutStream(stream StreamReqData) returns (StreamResData);//  客户端流模式
  rpc AllStream(stream StreamReqData) returns (stream StreamResData);//  双向流模式
}

// 请求数据结构体
message StreamReqData{
  string data = 1;
}

// 响应数据结构体
message StreamResData{
  string data = 1;
}

生成客户端代理stub程序、服务端代理stub程序、接口相关代码的命令:
protoc --go_out=. --go-grpc_out=. stream.proto

3、服务端代码 server.go

package main

import (
	"Go_Bible/stream_grpc_test/proto"
	"fmt"
	"google.golang.org/grpc"
	"net"
	"sync"
	"time"
)

// 端口
const PORT = ":8088"

// 自定义服务结构体
type MyServer struct {
	proto.UnimplementedGreeterServer
}

// 实现服务端流模式方法
func (s *MyServer) GetStream(req *proto.StreamReqData, srvStr proto.Greeter_GetStreamServer) error {
	i := 0
	for {
		i++
		// 向客户端发送响应结构体
		_ = srvStr.SendMsg(&proto.StreamResData{
			Data:fmt.Sprintf("%v", time.Now().Unix()),
		})
		time.Sleep(time.Second)
		// 每隔一秒发送1次,总共发送10次
		if i >= 10 {
			break
		}
	}
	return nil
}

// 实现客户端流模式方法
func (s *MyServer) PutStream(cliStr proto.Greeter_PutStreamServer) error {
	for {
		if data, err := cliStr.Recv(); err != nil {
			fmt.Println("接受客户端的流数据失败:" + err.Error())
			break
		}else {
			fmt.Println("接受到客户端的流数据成功:" + data.Data)
		}
	}
	return nil
}

// 实现双向流模式方法
func (s *MyServer) AllStream(allStr proto.Greeter_AllStreamServer) error {
	wg := sync.WaitGroup{}
	wg.Add(2)
	go func() {
		defer wg.Done()
		i := 0
		for {
			i++
			// 向客户端发送响应结构体
			_ = allStr.SendMsg(&proto.StreamResData{Data: fmt.Sprintf("我是服务器 %d", i)})
			time.Sleep(time.Second)
			if i >= 10 {
				break
			}
		}
	}()

	go func() {
		defer wg.Done()
		for {
			data, _ := allStr.Recv()
			fmt.Println("服务端接受到客户端的流数据成功:" + data.Data)
		}
	}()
	// 等待相关协程开启调用完成
	wg.Wait()
	return nil
}

func main() {
	// 1、监听端口
	listener, err := net.Listen("tcp", PORT)
	if err != nil {
		panic("监听端口失败:" + err.Error())
	}
	// 2、创建服务
	server := grpc.NewServer()
	// 3、注册服务
	proto.RegisterGreeterServer(server, &MyServer{})
	// 4、启动服务
	err = server.Serve(listener)
	if err != nil {
		panic("启动服务失败:" + err.Error())
	}
}

4、客户端代码client.go

package main

import (
	"Go_Bible/stream_grpc_test/proto"
	"context"
	"fmt"
	"google.golang.org/grpc"
	"strconv"
	"sync"
	"time"
)

// testGetStream 测试服务端流模式
func testGetStream(client proto.GreeterClient){
	res, err := client.GetStream(context.Background(), &proto.StreamReqData{Data: "我是客户端"})
	if err != nil {
		panic("服务端流模式,从服务端获取数据失败:" + err.Error())
	}
	for {
		data, err := res.Recv()
		if err != nil {
			fmt.Println("从服务端获取数据失败:" + err.Error())
			break
		}
		fmt.Println("从服务端获取到数据成功:" + data.Data)
	}
}

// testPutStream 测试客户端流模式
func testPutStream(client proto.GreeterClient){
	putStrClient, err := client.PutStream(context.Background())
	if err != nil {
		panic("客户端流模式,向服务端发送数据失败:" + err.Error())
	}
	i := 0
	for {
		i++
		fmt.Println(i)
		if err = putStrClient.Send(&proto.StreamReqData{Data: strconv.Itoa(i)}); err != nil {
			fmt.Println("喜爱那个服务端发送数据失败:" + err.Error())
			break
		}
		time.Sleep(time.Second)
		if i >= 10 {
			break
		}
	}
}

// testAllStream 测试双向流模式
func testAllStream(client proto.GreeterClient){
	allStrClient, err := client.AllStream(context.Background())
	if err != nil {
		panic("双向流模式获取失败:" + err.Error())
	}
	wg := sync.WaitGroup{}
	wg.Add(2)
	// 向服务端发送数据 因为服务端会从客户端源源不断获取数据,因此服务端也不会自动关闭
	go func() {
		defer wg.Done()
		i := 0
		for {
			i++
			err = allStrClient.Send(&proto.StreamReqData{Data: fmt.Sprintf("双向流模式发送的数据:%d", i)})
			if err != nil {
				fmt.Println("双向流模式向服务端发送数据失败:" + err.Error())
				break
			}
			if i >= 10 {
				break
			}
		}
	}()

	// 从服务端接受数据,因为双向流模式时,客户端需要从服务端源源不断接受数据,因此不会关闭
	go func() {
		defer wg.Done()
		for {
			data, err := allStrClient.Recv()
			if err != nil {
				fmt.Println("双向流模式从服务端接受数据失败:" + err.Error())
				break
			}
			fmt.Println("双向流模式收到服务端消息:" + data.Data)
		}
	}()
	wg.Wait()
}


func main() {

	//	1、拨号
	conn, err := grpc.Dial("localhost:8088", grpc.WithInsecure())
	if err != nil {
		panic("连接失败:" + err.Error())
	}
	// 关闭连接
	defer conn.Close()
	//2、创建客户端
	client := proto.NewGreeterClient(conn)
	/*3、测试服务端流模式*/
	//testGetStream(client)

	/*4、测试客户端流模式*/
	//testPutStream(client)

	/*5、测试双向流模式*/
	testAllStream(client)
}

5、测试说明

先启动服务端server.go
再启动客户端client.go,调用对应函数进行测试

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/589608.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【算法入门教育赛1E】最长公共前缀 - 字符串哈希 | 二分 | C++题解与代码

题目链接:https://www.starrycoding.com/problem/163 题目描述 牢 e e e在 S t a r r y C o d i n g StarryCoding StarryCoding的入门教育赛报名单上遇到了许多名字 s 1 , s 2 , . . . , s n s_1, s_2,...,s_n s1​,s2​,...,sn​,他想知道由这些人的…

网络安全风险里的威胁建模

文章目录 前言一、威胁建模的必要性二、威胁建模的过程三、威胁建模框架及方法1、NIST威胁模型框架2、STRIDE Model框架3、DREAD框架4、PASTA流程5、LINDDUN框架6、TRIKE知识库7、安全决策树四、威胁建模应用实践前言 网络安全的本质是攻防双方的对抗与博弈。然而,由于多种攻…

python学习笔记B-20:序列实战--处理千年虫

将2位数表达的年份,转换为用4位数表达: print("将列表中的2位数年份转换为4位数年份") lst[88,89,90,00,99] print(lst) for index in range(len(lst)):if len(str(lst[index]))2:lst[index] 1900int(lst[index])elif len(str(lst[index]))1…

微信小程序demo-----制作文章专栏

前言:不管我们要做什么种类的小程序都涉及到宣传或者扩展其他业务,我们就可以制作一个文章专栏的页面,实现点击一个专栏跳转到相应的页面,页面可以有科普类的知识或者其他,然后页面下方可以自由发挥,添加联…

网盘——分享文件——逻辑设计

本文主要讲解关于网盘文件操作部分的分享文件的逻辑设计部分,主要步骤如下: 目录 1、实施步骤: 2、代码实现 2.1、添加分享文件协议 2.2、添加取消槽函数 2.3、关联取消选择的槽函数 2.4、添加取消槽函数的定义 2.5、添加全选函数槽函…

小程序地理位置接口权限直接抄作业

小程序地理位置接口有什么功能? 随着小程序生态的发展,越来越多的小程序开发者会通过官方提供的自带接口来给用户提供便捷的服务。但是当涉及到地理位置接口时,却经常遇到申请驳回的问题,反复修改也无法通过,给的理由也…

rabbitMq 0 到1

前言 工作中MQ的使用场景是数不胜数,每个公司的技术选型又不太一样,用的哪个MQ,我们必须要先玩起来,RabbitMQ在windows安装遇到很多问题,博客也是五花八门,算了还是自己搞吧,记录一下&#xff…

C#描述-计算机视觉OpenCV(3):重映射

C#描述-计算机视觉OpenCV(3):重映射 前言色彩波形图像重映射 前言 C#描述-计算机视觉OpenCV(1):基础操作 C#描述-计算机视觉OpenCV(2):图像处理 在前文中,描…

2.2 Java全栈开发前端+后端(全栈工程师进阶之路)-前端框架VUE3-基础-Vue基本语法

文本渲染指令 文本渲染指令-v-html与v-text Vue使用了基于HTML的模板语法,允许开发者声明式地将DOM绑定至底层Vue实例的数据。所有Vue的模板都是 合法的HTML,所以能被遵循规范的浏览器和HTML解析器解析。 在前面,我们一直使用的是字符串插…

探索科技园区的创新应用架构

在当今科技快速发展的时代,科技园区已经成为了创新和技术发展的孵化器和聚集地。在这样的环境中,科技园区的应用架构扮演着至关重要的角色,它不仅需要支持各种创新型企业和科技项目的发展,还需要提供高效的技术基础设施和服务。下…

python 11Pandas数据可视化实验

实验目的: 学会使用Pandas操作数据集,并进行可视化。 数据集描述: 该数据集是CNKI中与“中药毒理反应”相关的文献信息,包含文章题目、作者、来源(出版社)、摘要、发表时间等信息。 实验要求&#xff1…

ubuntu外置网卡配置AP模式

外置网卡RTL8811CU设置 UBUNTU使用RTL8811CU网卡(包含树莓派) 外置网卡配置AP模式流程 1. 检查网卡支持情况(是否支持AP模式) iw list找到以上部分,发现支持AP 2. 安装依赖 sudo apt-get update sudo apt-get in…

39 死锁

目录 1.死锁 2.线程同步 3.条件变量 4.案例 死锁 概念 死锁是指在一组进程中的各个进程均占有不会释放的资源,但因互相申请被其他进程所占用不会释放的资源而处于的一种永久等待状态 四个必要条件 互斥条件:一个资源每次只能被一个执行流使用 请求…

MFC 列表控件修改实例(源码下载)

1、本程序基于前期我的博客文章《MFC下拉菜单打钩图标存取实例(源码下载)》 2、程序功能选中列表控件某一项,修改这一项的按钮由禁止变为可用,双击这个按钮弹出对话框可对这一项的记录数据进行修改,点击确定保存修改数…

SpirngBoot整合快递100

目录 一、注册快递100 二、技术文档地址 三、需要认证的key和comcumer 四、spring boot 整合快递 100使用 4.1 引入快递100和hutool的依赖 4.2 将key和comcumer写入application.properties文件中 4.3 新建一个modle,用于将查出来的json数据转成对象 4.4 新建一个controll…

golang 基础知识细节回顾

之前学习golang的速度过于快,部分内容有点囫囵吞枣的感觉,写gorm过程中有很多违反我常识的地方,我通过复习去修正了我之前认知错误和遗漏的地方。 itoa itoa自增的作用在编辑error code时候作用很大,之前编辑springboot的error c…

python从0开始学习

目录 前言 1、print函数 2、input函数 3、保留字和标识符 总结 前言 本篇文章我们开辟一个新的学习模块:python。python是一个十分简洁实用的编程语言,我们将从0开始学习python 1、print函数 print(*args, sep , end\n, fileNone, flushFalse) pytho…

2024五一数学建模C题煤矿深部开采冲击地压危险预测原创论文分享

大家好,从昨天肝到现在,终于完成了2024五一数学建模竞赛C题的完整论文啦。 实在精力有限,具体的讲解大家可以去讲解视频: 2024五一数学建模C题完整原创论文讲解,手把手保姆级教学!_哔哩哔哩_bilibili 202…

[1678]旅游景点信息Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 JSP 旅游景点信息管理系统是一套完善的java web信息管理系统,对理解JSP java编程开发语言有帮助,系统具有完整的源代码和数据库,系统主要采用B/S模式开发。开发环境为TOMCAT7.0,Myeclipse8.5开发,数据库为Mysql…

在idea中连接mysql

IDE(集成开发环境)是一种软件应用程序,它为开发者提供编程语言的开发环境,通常集成了编码、编译、调试和运行程序的多种功能。一个好的IDE可以大幅提高开发效率,尤其是在进行大型项目开发时。IDE通常包括以下几个核心组…
最新文章