golang grpc初体验

grpc 是一个高性能、开源和通用的 RPC 框架,面向服务端和移动端,基于 HTTP/2 设计。目前支持c、java和go,分别是grpc、grpc-java、grpc-go,目前c版本支持c、c++、node.js、ruby、python、objective-c、php和c#。grpc官网 grpc-go
在这里插入图片描述
ProtoBuf(全称Protocol Buffer)是数据结构序列化和反序列化框架,ProtoBuf是Google推出的一款轻量高效的数据化数据存储格式,性能比json、xml强,ProtoBuf经历了ProtoBuf2和ProtoBuf3,ProtoBuf3比ProtoBuf简化了很多,目前主流的是ProtoBuf3.
优点:
1.性能:压缩性好、序列化和反序列化快(比xml和json快2-100倍)、传输速度快
2.便捷性:使用简单(自动生成序列化和反序列化代码)、维护成本低(只支持proto文件)、向后兼容(不必破坏旧格式)、加密型号
3.跨语言:跨平台、支持各种主流语言
缺点:
1.通用性差:json可以任何语言都支持,但是protobuf需要专门的解析库
2.自解释性差:只有通过proto文件才能了解数据结构
protoBuf安装并配置环境变量官网
1.编辑环境变量文件‌:vim ~/.zshrc
‌2.添加环境变量‌:

export PATH="$PATH:/usr/local/go/src/GolangStudy/protoc-28.2-osx-x86_64/bin"

3.使配置生效‌:保存并关闭编辑器后,在终端中输入source ~/.zshrc
命令,使更改生效。
4.验证

 protoc --version

安装protoBuf的go依赖包

go get github.com/golang/protobuf/protoc-gen-go

helloworld.proto

syntax = "proto3";

// 生成 proto 文件所在包路径
package protos;
// 影响go文件生成位置和包名
option go_package = "GolangStudy/Introduction/grpc/protos";
message HelloRquest{
    string name=1;//1是编号不是值
}

项目目录结构
在这里插入图片描述
转换命令(第一种命令使用grpc,会比第二种多很多)

protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative helloworld.proto 
protoc --go_out=/usr/local/go/src/GolangStudy/GolangStudy --proto_path=/usr/local/go/src/GolangStudy/GolangStudy/Introduction/grpc/protos --go_opt=module=GolangStudy helloworld.proto

调用并比较跟json格式的区别

package main

import (
	"GolangStudy/Introduction/grpc/protos"
	"encoding/json"
	"fmt"

	"github.com/golang/protobuf/proto"
)

type Hello struct {
	Name string `json:"name"`
}

func main() {
	req := protos.HelloRquest{
		Name: "bobby",
	}
	jsonStruct := Hello{Name: "bobby"}
	jsonRsp, _ := json.Marshal(jsonStruct)
	fmt.Println(len(string(jsonRsp)))
	rsp, _ := proto.Marshal(&req)
	fmt.Println(len(string(rsp)))
}

json长度是15,而protobuf长度是7

grpc四种数据流

简单模式(simple rpc):客户端发起一次请求,服务端响应一个数据
服务端数据流模式(server-side streaming rpc):客户端发起一次请求,服务端返回一段连续的数据流。(客户端向服务端发送一个股票代码,服务端就把该股票的实时数据源源不断的返回给客户端)
客户端数据流模式(client-side streaming rpc):客户端源源不断的项向服务端发送数据流,而在发送结束后,由服务器返回一个响应(物流网终端向服务器报送数据)
双向数据流模式(bidirectional streaming rpc):客户端和服务端都可以向双方发送数据流,双方的数据可以同时互相发送,可以实现实时交互(聊天机器人)

grpc简单模式

目录结构
在这里插入图片描述

proto代码

syntax = "proto3";

// 生成proto文件所在包路径
package protos;
option go_package = ".;proto";
// 影响go文件生成位置和包名
service Greeter{
    rpc SayHello(HelloRquest)returns(HelloReply);//hello接口
}
message HelloRquest{
    string name=1;//1是编号不是值
}
message HelloReply{
    string message=1;
}

生成go文件

protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative helloworld.proto

使用接口删除这一行(可能是生成方式的问题)
在这里插入图片描述
server端

package main

import (
	"GolangStudy/Introduction/grpc/example2/proto"
	"context"
	"net"

	"google.golang.org/grpc"
)

type Server struct {
}

func (s *Server) SayHello(ctx context.Context, request *proto.HelloRquest) (*proto.HelloReply, error) {
	return &proto.HelloReply{
		Message: "helo" + request.Name,
	}, nil
}
func main() {
	g := grpc.NewServer()
	proto.RegisterGreeterServer(g, &Server{})
	lis, err := net.Listen("tcp", "0.0.0.0:8080")
	if err != nil {
		panic("failed to listen:" + err.Error())
	}
	err = g.Serve(lis)
	if err != nil {
		panic("failed to start ")
	}
}

client端

package main

import (
	"GolangStudy/Introduction/grpc/example2/proto"
	"context"
	"fmt"

	"google.golang.org/grpc"
)

func main() {
	conn, err := grpc.Dial("127.0.0.1:8080", grpc.WithInsecure())
	if err != nil {
		panic(err)
	}
	defer conn.Close()
	c := proto.NewGreeterClient(conn)
	r, err := c.SayHello(context.Background(), &proto.HelloRquest{
		Name: "bobby",
	})
	if err != nil {
		panic(err)
	}
	fmt.Println(r.Message)
}

grpc流模式

proto

syntax = "proto3";

// 生成proto文件所在包路径
package protos;
option go_package = ".;proto";
// 影响go文件生成位置和包名
service Greeter{
    rpc GetStream(StreamReqData)returns(stream SteramResData);//服务端流模式
    rpc PostStream(stream StreamReqData)returns(stream SteramResData);//客户端流模式
    rpc AllStream(stream StreamReqData)returns(stream SteramResData);//双向流模式
}
message StreamReqData{
    string data=1;
}
message SteramResData{
    string data=1;
}

生成go文件

 protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative stream.proto

删除
在这里插入图片描述
server

package main

import (
	"GolangStudy/Introduction/grpc/stream_grpc_test/proto"
	"fmt"
	"net"
	"sync"
	"time"

	"google.golang.org/grpc"
)

const PORT = ":50052"

type server struct {
}

func (s *server) GetStream(req *proto.StreamReqData, res proto.Greeter_GetStreamServer) error {
	i := 0
	for {
		i++
		_ = res.Send(&proto.SteramResData{
			Data: fmt.Sprintf("%v", time.Now().Unix()),
		})
		time.Sleep(time.Second)
		if i > 10 {
			break
		}
	}
	return nil
}
func (s *server) PostStream(cliStr proto.Greeter_PostStreamServer) error {
	for {
		if a, err := cliStr.Recv(); err != nil {
			fmt.Println(err)
			break
		} else {
			fmt.Println(a.Data)
		}
	}
	return nil
}
func (s *server) AllStream(allStr proto.Greeter_AllStreamServer) error {
	wg := sync.WaitGroup{}
	wg.Add(2)
	go func() {
		defer wg.Done()
		for {
			data, _ := allStr.Recv()
			fmt.Println("收到客户端消息:" + data.Data)
		}
	}()
	go func() {
		defer wg.Done()
		for {
			allStr.Send(&proto.SteramResData{
				Data: "我是服务器",
			})
			time.Sleep(time.Second)
		}
	}()
	wg.Wait()
	return nil
}
func main() {
	lis, err := net.Listen("tcp", PORT)
	if err != nil {
		panic(err)
	}
	s := grpc.NewServer()
	proto.RegisterGreeterServer(s, &server{})
	err = s.Serve(lis)
	if err != nil {
		panic("failed to start ")
	}
}

client

package main

import (
	"GolangStudy/Introduction/grpc/stream_grpc_test/proto"
	"context"
	"fmt"
	"sync"
	"time"

	"google.golang.org/grpc"
)

func main() {
	conn, err := grpc.Dial("127.0.0.1:50052", grpc.WithInsecure())
	if err != nil {
		panic(err)
	}
	defer conn.Close()
	//服务端流模式
	// c := proto.NewGreeterClient(conn)
	// res, _ := c.GetStream(context.Background(), &proto.StreamReqData{Data: "mooc"})
	// for {
	// 	a, err := res.Recv() //socket编程send recv
	// 	if err != nil {
	// 		fmt.Println(err)
	// 		break
	// 	}
	// 	fmt.Println(a)

	// }

	// //客户端流模式
	// c := proto.NewGreeterClient(conn)
	// putS, _ := c.PostStream(context.Background())
	// i := 0
	// for {
	// 	i++
	// 	_ = putS.Send(&proto.StreamReqData{
	// 		Data: fmt.Sprintf("mooc%d", i),
	// 	})
	// 	time.Sleep(time.Second)
	// 	if i > 10 {
	// 		break
	// 	}
	// }

	//双向流模式
	c := proto.NewGreeterClient(conn)
	allStr, _ := c.AllStream(context.Background())
	wg := sync.WaitGroup{}
	wg.Add(2)
	go func() {
		defer wg.Done()
		for {
			data, _ := allStr.Recv()
			fmt.Println("收到服务器消息:" + data.Data)
		}
	}()
	go func() {
		defer wg.Done()
		for {
			allStr.Send(&proto.StreamReqData{
				Data: "我是客户端",
			})
			time.Sleep(time.Second)
		}
	}()
	wg.Wait()
}

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

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

相关文章

Visual Studio 字体与主题推荐

个人推荐,仅供参考: 主题:One Monokai VS Theme 链接:One Monokai VS Theme - Visual Studio Marketplacehttps://marketplace.visualstudio.com/items?itemNameazemoh.onemonokai 效果: 字体:JetBrain…

[RabbitMQ] Spring Boot整合RabbitMQ

🌸个人主页:https://blog.csdn.net/2301_80050796?spm1000.2115.3001.5343 🏵️热门专栏: 🧊 Java基本语法(97平均质量分)https://blog.csdn.net/2301_80050796/category_12615970.html?spm1001.2014.3001.5482 🍕 Collection与…

Scrapy 爬虫的大模型支持

使用 Scrapy 时,你可以轻松使用大型语言模型 (LLM) 来自动化或增强你的 Web 解析。 有多种使用 LLM 来帮助进行 Web 抓取的方法。在本指南中,我们将在每个页面上调用一个 LLM,从中抽取我们定义的一组属性,而无需编写任何选择器或…

C++和OpenGL实现3D游戏编程【连载13】——多重纹理混合详解

🔥C++和OpenGL实现3D游戏编程【目录】 1、本节要实现的内容 前面说过纹理贴图能够大幅提升游戏画面质量,但纹理贴图是没有叠加的。在一些游戏场景中,要求将非常不同的多个纹理(如泥泞的褐色地面、绿草植密布的地面、碎石遍布的地面)叠加(混合)起来显示,实现纹理间能够…

多区域OSPF路由协议

前言 之前也有过关于OSPF路由协议的博客,但都不是很满意,不是很完整。现在也是听老师讲解完OSPF路由协议,感触良多,所以这里重新整理一遍。这次应该是会满意的 一些相关概念 链路状态 链路指路由器上的一个接口,链路状…

【社保通-注册安全分析报告-滑动验证加载不正常导致安全隐患】

前言 由于网站注册入口容易被黑客攻击,存在如下安全问题: 暴力破解密码,造成用户信息泄露短信盗刷的安全问题,影响业务及导致用户投诉带来经济损失,尤其是后付费客户,风险巨大,造成亏损无底洞…

新手教学系列——爬虫异步并发注意事项

引言 爬虫是网络数据采集中不可或缺的工具,很多程序员在入门时会遇到这样的问题:为什么我的爬虫这么慢?尤其在面对大量数据时,单线程爬虫的速度可能让人捶胸顿足。随着爬虫规模的增大,异步并发成为了提高爬取效率的关键。然而,异步并发并不像表面看起来那么简单,如果没…

初识Linux · 进程替换

目录 前言: 1 直接看代码和现象 2 解释原理 3 将代码改成多进程版本 4 认识所有函数并使用 前言: 由前面的章节学习,我们已经了解了进程状态,进程终止以及进程等待,今天,我们学习进程替换。进程替换我…

Python:import语句的使用(详细解析)(一)

相关阅读 Pythonhttps://blog.csdn.net/weixin_45791458/category_12403403.html?spm1001.2014.3001.5482 import语句是Python中一个很重要的机制,允许在一个文件中访问另一个文件的函数、类、变量等,本文就将进行详细介绍。 在具体谈论import语句前&a…

hbuilderx+uniapp+Android宠物用品商城领养服务系统的设计与实现 微信小程序沙箱支付

目录 项目介绍支持以下技术栈:具体实现截图HBuilderXuniappmysql数据库与主流编程语言java类核心代码部分展示登录的业务流程的顺序是:数据库设计性能分析操作可行性技术可行性系统安全性数据完整性软件测试详细视频演示源码获取方式 项目介绍 顾客 领养…

设计模式、系统设计 record part02

软件设计模式: 1.应对重复发生的问题 2.解决方案 3.可以反复使用 1.本质是面向对象 2.优点很多 1.创建型-创建和使用分离 2.结构型-组合 3.行为型-协作 571123种模式 UML-统一建模语言-Unified Modeling Language 1.可视化,图形化 2.各种图(9…

PostgreSQL 任意命令执行漏洞(CVE-2019-9193)

记一次授权攻击通过PostgreSql弱口令拿到服务器权限的事件。 使用靶机复现攻击过程。 过程 在信息收集过程中,获取到在公网服务器上开启了5432端口,尝试进行暴破,获取到数据库名为默认postgres,密码为1 随后连接进PostgreSql …

【CSS in Depth 2 精译_043】6.5 CSS 中的粘性定位技术 + 本章小结

当前内容所在位置(可进入专栏查看其他译好的章节内容) 第一章 层叠、优先级与继承(已完结)第二章 相对单位(已完结)第三章 文档流与盒模型(已完结)第四章 Flexbox 布局(已…

项目定位与服务器(SERVER)模块划分

目录 定位 HTTP协议以及HTTP服务器 高并发服务器 单Reactor单线程 单Reactor多线程 多Reactor多线程 模块划分 SERVER模块划分 Buffer 模块 Socket模块 Channel 模块 Connection模块 Acceptor模块 TimerQueue模块 Poller模块 EventLoop模块 TcpServer模块 SE…

HTML5+CSS+JavaScript剪子石头布游戏

HTML5CSSJavaScript剪子石头布游戏 用HTML5CSSJavaScript剪子石头布游戏实现剪子石头布游戏,游戏有成绩计数,人、机输赢情况,及平局情况。 ✂代表剪刀,▉代表石头,▓ 代表布,给出人机双方的出拳情况 游戏…

【LeetCode每日一题】——17.电话号码的字母组合

文章目录 一【题目类别】二【题目难度】三【题目编号】四【题目描述】五【题目示例】六【题目提示】七【解题思路】八【时间频度】九【代码实现】十【提交结果】 一【题目类别】 回溯 二【题目难度】 中等 三【题目编号】 17.电话号码的字母组合 四【题目描述】 给定一个…

看480p、720p、1080p、2k、4k、视频一般需要多大带宽呢?

看视频都喜欢看高清,那么一般来说看电影不卡顿需要多大带宽呢? 以4K为例,这里引用一位网友的回答:“视频分辨率4092*2160,每个像素用红蓝绿三个256色(8bit)的数据表示,视频帧数为60fps,那么一秒…

向日葵软件安装失败

一开始点击普通下载,下载完毕后,安装了好几次也没安装成功。 查找解决方法后 在控制面板-程序和功能,寻找已安装 的向日葵 手动卸载已安装但是又没成功的向日葵 重新点击普通下载,下载完安装还是失败。 于是改为安全下载&…

k8s的学习和使用

为什么用k8s,不用docker? k8s更适合复杂的微服务架构和大规模的容器应用。 Pods(Pod) Pod是k8s最小可部署单元,他包含一个或多个相关容器。这些容器共享网络命名空间和存储卷,他们通常协同工作来构成一个应用程序。 Serv…