Go语言操作grpc详细使用

2023-05-16

Go语言操作grpc详细使用

  • 零、参考链接
  • 一、protobuf的详细使用
  • 二、grpc与protobuf的go文件的生成
    • 1.安装两个插件
    • 2.写proto文件
    • 3.编译proto文件,生成go文件
  • 三、grpc的详细使用
    • 1.一元RPC模式
    • 2.客户端流RPC模式
    • 3.服务器端流RPC模式
    • 4.双向流RPC模式

零、参考链接

视频:90分钟搞懂分布式RPC开源框架

一、protobuf的详细使用

protobuf的单独使用

二、grpc与protobuf的go文件的生成

1.安装两个插件

go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest

2.写proto文件

syntax = "proto3";

option go_package = "../proto_go;protos";


message Person{
  string name = 1;
  int32 id = 2;
}

message IPhoneInfo {
  string name = 1;
  int32 id = 2;
  string email = 3;

  enum phoneType{
    MOBILE = 0;
    HOME = 1;
    WORK = 2;
  }

  message phoneNumber{
    string number = 1;
    phoneType type = 2;
  }

  phoneNumber phones = 4;
}

service ProdService{    //grpc服务,这是最简单的一元grpc模式
  rpc GetProdStock(Person) returns (IPhoneInfo);
}

3.编译proto文件,生成go文件

在pbfiles的文件目录下,运行下面的命令

protoc --go_out=../proto_go --go_opt=paths=source_relative --go-grpc_out=../proto_go --go-grpc_opt=paths=source_relative echo.proto

会在proto_go下生成两个文件
1111

注意:每次修改了pbfiles中的.proto文件之后,都要重新编译生成两个文件

三、grpc的详细使用

可以直接看这个:gRPC开发: gRPC的四种通信模式

1.一元RPC模式

proto文件,最后的服务函数写这个,然后编译文件。

service ProdService{
  rpc GetProdStock(Person) returns (IPhoneInfo);
}

客户端

package main

import (
	"context"
	"fmt"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
	protos "grpc/proto_go"
	"log"
	"time"
)

var person = []string{"cjs", "dh", "jay", "tom"}

func main() {
	conn, err := grpc.Dial("localhost:8080", grpc.WithTransportCredentials(insecure.NewCredentials()))
	if err != nil {
		log.Fatalf("Did not connect:%v", err)
	}
	defer conn.Close()
	c := protos.NewProdServiceClient(conn)

	for _, name := range person {
		p := &protos.Person{
			Name: name,
			Id:   1,  //无用瞎写的
		}
		ack, err := c.GetProdStock(context.Background(), p)
		if err != nil {
			panic(err)
		}
		fmt.Println(ack)
		time.Sleep(time.Second)
	}
//并发协程测试,也是没问题的
	var wg sync.WaitGroup
	wg.Add(len(person))
	for _, name := range person {
		p := &protos.Person{
			Name: name,
			Id:   1,
		}

		go func(*protos.Person) {
			ack, err := c.GetProdStock(context.Background(), p)
			if err != nil {
				panic(err)
			}
			fmt.Println(ack)
			wg.Done()
		}(p)

	}

	wg.Wait()
}

服务端

package main

import (
	"context"
	"fmt"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
	protos "grpc/proto_go"
	"net"
)

type server struct {
	protos.UnimplementedProdServiceServer
	//或者在这里面添加你需要的字段
}

func (s *server) GetProdStock(ctx context.Context, req *protos.Person) (*protos.IPhoneInfo, error) {
	name := req.GetName()
	fmt.Println(name)
	if info, ok := AddressBook[name]; ok {
		return info, nil
	}
	return nil, status.Errorf(codes.NotFound, "Order does not exist.:", req.Name, req.Id)
}

var AddressBook map[string]*protos.IPhoneInfo

func main() {
	//0.创建db
	DBAddressBook()
	//1.创建rpcserver
	rpcs := grpc.NewServer()
	//2.将上一步创建的rpc服务器,和对应的服务,进行注册
	protos.RegisterProdServiceServer(rpcs, &server{})
	//3.创建一个监听服务
	listen, err := net.Listen("tcp", ":8080")
	if err != nil {
		panic(err)
	}
	defer listen.Close()
	//4.启动rpc服务
	if err = rpcs.Serve(listen); err != nil {
		panic(err)
	}
}

func DBAddressBook() {
	AddressBook = make(map[string]*protos.IPhoneInfo)
	AddressBook["cjs"] = &protos.IPhoneInfo{
		Name:  "cjs",
		Id:    1,
		Email: "cjs_svip@163.com",
		Phones: &protos.IPhoneInfoPhoneNumber{
			Number: "18131371662",
			Type:   1,
		},
	}
	AddressBook["dh"] = &protos.IPhoneInfo{
		Name:  "dh",
		Id:    2,
		Email: "dh_svip@163.com",
		Phones: &protos.IPhoneInfoPhoneNumber{
			Number: "18131371663",
			Type:   2,
		},
	}
	AddressBook["jay"] = &protos.IPhoneInfo{
		Name:  "jay",
		Id:    3,
		Email: "jay_svip@163.com",
		Phones: &protos.IPhoneInfoPhoneNumber{
			Number: "18131371664",
			Type:   protos.IPhoneInfo_MOBILE, //eunm的坑,注意这里无论是写0还是写这个,都解析不出来
		},
	}
	AddressBook["tom"] = &protos.IPhoneInfo{
		Name:  "tom",
		Id:    4,
		Email: "tom_svip@163.com",
		Phones: &protos.IPhoneInfoPhoneNumber{
			Number: "18131371665",
			Type:   1,
		},
	}
}

2.客户端流RPC模式

proto文件,最后的服务函数写这个,然后编译文件。

message AddressBook{
  repeated IPhoneInfo people = 1;
}

service ProdService{
  rpc GetProdStock(Person) returns (IPhoneInfo);  //上一步中的,留着也没问题
  rpc GetCStreamStock(stream Person) returns (AddressBook);
}

客户端

package main

import (
	"context"
	"fmt"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
	protos "grpc/proto_go"
	"log"
)

var person = []string{"cjs", "dh", "jay", "tom"}

func main() {
	conn, err := grpc.Dial("localhost:8080", grpc.WithTransportCredentials(insecure.NewCredentials()))
	if err != nil {
		log.Fatalf("Did not connect:%v", err)
	}
	defer conn.Close()
	//1.依托链接,创建rpc客户端
	c := protos.NewProdServiceClient(conn)
	//2.依托链接,获取客户端流传输器
	stream, err := c.GetCStreamStock(context.Background())
	if err != nil {
		panic(err)
	}

	for _, name := range person {
		p := &protos.Person{
			Name: name,
			Id:   1,
		}
		//3.利用stream的send实现流传输
		err := stream.Send(p)
		if err != nil {
			panic(err)
		}
	}

	recv, err := stream.CloseAndRecv() //4.结束客户端流,接收数据
	if err != nil {
		panic(err)
	}
	fmt.Println(recv)

}

服务端(把这个函数添加到上一步骤的服务端文件中即可)

func (s *server) GetCStreamStock(stream protos.ProdService_GetCStreamStockServer) error {
	book := protos.AddressBook{People: make([]*protos.IPhoneInfo, 0)}
	for {
		recv, err := stream.Recv()
		if err == io.EOF {
			return stream.SendAndClose(&book)
		}
		name := recv.GetName()
		fmt.Println(name)
		if info, ok := AddressBook[name]; ok {
			book.People = append(book.People, info)
		}
	}
}

3.服务器端流RPC模式

proto文件,最后的服务函数写这个,然后编译文件。

message SearchPerson{
  repeated Person per = 1;
}
service ProdService{
  rpc GetProdStock(Person) returns (IPhoneInfo);  //上一步中的,留着也没问题
  rpc GetCStreamStock(stream Person) returns (AddressBook);  //上一步中的,留着也没问题
  rpc GetSStreamStock(SearchPerson) returns (stream IPhoneInfo);
}

客户端

package main

import (
	"context"
	"fmt"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
	protos "grpc/proto_go"
	"io"
	"log"
)

var person = []string{"cjs", "dh", "jay", "tom"}

func main() {
	conn, err := grpc.Dial("localhost:8080", grpc.WithTransportCredentials(insecure.NewCredentials()))
	if err != nil {
		log.Fatalf("Did not connect:%v", err)
	}
	defer conn.Close()
	c := protos.NewProdServiceClient(conn)
	//1.因为是服务端流模式,客户端可以把数据一次性发送过去
	lists := make([]*protos.Person, 0)
	for _, name := range person {
		p := &protos.Person{
			Name: name,
			Id:   1,
		}
		lists = append(lists, p)
	}
	//2.以服务端流接收方式,发送数据
	ackStream, err := c.GetSStreamStock(context.Background(), &protos.SearchPerson{Per: lists})
	if err != nil {
		panic(err)
	}
	//3.循环接收服务端的流数据
	for {
		recv, err := ackStream.Recv()
		if err != nil && err != io.EOF {
			panic(err)
		} else if err == io.EOF { //4.当EOF的时候代表没数据了
			break
		}

		fmt.Println(recv)
	}

}

服务端(把这个函数添加到上一步骤的服务端文件中即可)

func (s *server) GetSStreamStock(sp *protos.SearchPerson, stream protos.ProdService_GetSStreamStockServer) error {
	for _, person := range sp.Per {
		if info, ok := AddressBook[person.Name]; ok {
			err := stream.Send(info) //每次发送一部分数据
			if err != nil {
				return fmt.Errorf("error sending message to stream:%v", err)
			}
		}
	}
	return nil
}

4.双向流RPC模式

proto文件,最后的服务函数写这个,然后编译文件。

service ProdService{ 
  rpc GetProdStock(Person) returns (IPhoneInfo);//上一步中的,留着也没问题
  rpc GetCStreamStock(stream Person) returns (AddressBook);//上一步中的,留着也没问题
  rpc GetSStreamStock(SearchPerson) returns (stream IPhoneInfo);//上一步中的,留着也没问题
  rpc GetCSStreamStock(stream Person) returns (stream IPhoneInfo);
}

客户端

package main

import (
	"context"
	"fmt"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
	protos "grpc/proto_go"
	"io"
	"log"
	"sync"
	"time"
)

var person = []string{"cjs", "dh", "jay", "tom"}

func main() {
	conn, err := grpc.Dial("localhost:8080", grpc.WithTransportCredentials(insecure.NewCredentials()))
	if err != nil {
		log.Fatalf("Did not connect:%v", err)
	}
	defer conn.Close()
	c := protos.NewProdServiceClient(conn)
	stream, err := c.GetCSStreamStock(context.Background())
	if err != nil {
		panic(err)
	}

	var wg sync.WaitGroup
	wg.Add(1)
	go func() { //启动流接收协程
		for {
			recv, err := stream.Recv()
			if err != nil && err != io.EOF {
				panic(err)
			} else if err == io.EOF {
				wg.Done()
				return
			}
			fmt.Println(recv)
		}
	}()

	go func() { //启动流发送协程
		for _, name := range person {
			p := &protos.Person{
				Name: name,
				Id:   1,
			}

			err := stream.Send(p)
			if err != nil {
				panic(err)
			}

			time.Sleep(time.Second)
		}
		err := stream.CloseSend()
		if err != nil {
			panic(err)
		}
	}()

	wg.Wait()
}

服务端(把这个函数添加到上一步骤的服务端文件中即可)

func (s *server) GetCSStreamStock(stream protos.ProdService_GetCSStreamStockServer) error {
	for {
		recv, err := stream.Recv()
		if err != nil && err != io.EOF {
			panic(err)
		} else if err == io.EOF {
			return nil
		}
		if info, ok := AddressBook[recv.Name]; ok {
			fmt.Println(recv.Name)
			err := stream.Send(info)
			if err != nil {
				panic(err)
			}
		}
	}
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Go语言操作grpc详细使用 的相关文章

  • 错误:用于两个不同的模块路径

    当我尝试运行时出现错误go build 错误是这样的 go golang org x email protected cdn cgi l email protection used for two different module path
  • gRPC 客户端不处置 Channel

    我正在使用 gRPC 开发 net core 2 0 应用程序并发现一个问题 删除对 gRPC 客户端类实例的引用后 仍然存在使用资源 内存和处理器 的通道 示例代码 public class MyClient ClientBase pub
  • Docker compose找不到本地包

    因此 我在 GOlang 中创建了 REST api 和一个 grpc 服务 现在我想在 docker compose 中组合它 我的 docker compose 看起来像这样 version 3 services db image po
  • Grpc.Core.RpcException: 'Status (StatusCode = "不可用", Detail = "启动 gRPC 调用时出错

    如果您能告诉我导致问题的原因以及如何解决它 我将不胜感激 附 抱歉发布所有代码 只是我不确定哪个确切部分与问题相关 以下是异常的全文 Grpc Core RpcException Status StatusCode 不可用 Detail 启
  • proto 文件中定义的消息在最终的 dotnet 程序集中不可用

    我正在使用 dotnet standard 2 0 Visual Studio 2017 进行 gRPC 这就是我的整个项目的样子 消息 proto syntax proto3 package Messages message IdRequ
  • grpc/protobuffer 请求特定字段

    GraphQL 允许您请求特定字段 响应仅包含您请求的字段 例如 graphql 查询如下 hero name 将返回 data hero name R2 D2 作为 graphQl 查询 例如 hero name friends name
  • 使用gRPC共享非常大的文件

    我想使用 gRPC 在端点和服务器之间共享非常大的文件 超过 6GB 我当前工作的项目需要一个中央服务器 端点可以在其中上传和下载文件 限制之一是端点彼此不认识 但它们可以从公共总线相互接收和发送消息 为了实现该服务器及其与端点的通信 我正
  • C# gRPC 客户端拦截器设置授权标头

    我正在尝试为 gRPC 客户端创建一个拦截器 始终设置配置的 API 令牌 问题是我找不到设置的方法context Options Headers 如果我正在阅读文档 我需要致电WithHeaders方法 需要设置新的元数据 以便我可以添加
  • 如何发送格式在运行时确定的 gRPC 消息?

    我主要对用 Java 来做这件事感兴趣 但是看到任何语言的解决方案都会有帮助 根据我正在阅读的各种文档 gRPC 的默认工作流程是 Write a proto file 从该文件生成客户端和 或服务器代码 编写您的程序并将其与生成的代码一起
  • 如何解决grpc Deadline Exceeded错误?

    我有用go和python客户端编写的grpc服务器 有时会出现如下错误 eggs grpcio 1 0 0 py2 7 linux x86 64 egg grpc channel py line 432 in end unary respo
  • 如何检查连接到 GRPC 服务器的客户端

    为了为我的 GRPC 服务器 客户端设置提供更好的调试信息 我正在尝试寻找一个 APIgrpc server这使我能够检查哪些客户端连接到服务器 我发现的最有希望的问题是问题 它给出了如何在 Java GRPC 中执行此操作的起点 http
  • grpc go:如何在服务器端知道客户端何时关闭连接

    我正在使用 grpc go 我有一个 rpc 看起来大致像这样 196 service MyService 197 Operation 1 198 rpc Operation1 OperationRequest returns Operat
  • gRPC / Protobuf 接口版本控制

    假设我们使用 gRCP Protobuf 来连接许多应用程序 这些应用程序是由他们自己的团队以自己的速度开发和发布的 随着时间的推移 同一应用程序将出现不同版本 例如 安装在用户 PC 上的桌面应用程序 它们在定义的界面上使用不同的版本 虽
  • Java Grpc:使 dns 缓存无效

    我有一个 grpc 客户端指向一个解析为 2 个 IP 地址的 url 问题是 当一个服务器节点出现故障然后恢复时 grpc 客户端不会选择它 所有负载都会转移到单个节点 我尝试建议改变networkaddress cache ttl财产
  • gRPC 客户端在 Kubernetes 内重新连接

    如果我们在 Kubernetes Pod 中定义微服务 那么当服务 Pod 重新启动时 我们是否需要检测 gRPC 客户端重新连接 当 Pod 重新启动时 主机名不会更改 但我们不能保证 IP 地址保持不变 那么 gRPC 客户端是否仍然能
  • 如何在Python中使用gRPC处理自定义异常?

    我需要实现自定义异常来使用 Python 处理 gRPC 请求错误 对于 HTTP 请求 它很简单 当出现错误代码等时 请求库可以很好地捕获它 我正在寻找 gRPC 的类似方法来执行以下操作 try send gRPC request ex
  • Protobuf-java:合并两个原始对象而不连接重复字段

    我想合并两个复杂的原型对象protoA and protoB类型相同 如果两个对象中都设置了字段 则protoB应在生成的原型中设置 我可以使用 mergeFrom 功能 protoA toBuilder mergeFrom protoB
  • 如何将 Google proto 时间戳转换为 Java LocalDate?

    我们需要将 Google Protobuf 时间戳转换为正常日期 在这种情况下 有没有办法将 Google Proto 缓冲区时间戳转换为 JavaLocalDate直接地 tl dr 作为 UTC 时刻 转换为java time Inst
  • 仅使用 GRPC 连接到对话流 StreamingDetectIntent,卡在等待 responseStream.MoveNext

    我正在尝试将 DialogFlow API v2 与 Unity 结合使用 由于 Unity 还没有官方 SDK 所以我使用了 Grpc beta unity SDK 以及使用 Grpc 工具中的 Protobuf 和 protoc 创建的
  • 解决bazel中使用gRPC cpp时的依赖问题

    我正在尝试运行一个依赖 gRPC 的简单程序 我尝试了几个示例 但仍然出现以下错误 ERROR home git examples WORKSPACE 1 1 name git repository is not defined ERROR

随机推荐

  • keil中怎么添加自己的头文件,加入工程,保存路径。#include还用吗

    keil中怎么添加自己的头文件 xff0c 例如 xff1a 添加 include lt led h gt 要把它写在哪里 xff0c 保存在哪里 xff0c 才能编译后 xff0c 显示 include lt reg51 h gt inc
  • 面试题整理简历中深度学习机器学习相关的知识及linux操作系统命令

    深度学习与机器学习 都在整理关于后台的 xff0c 被问到后忘了 xff0c 尴尬 的确是我的问题 xff0c 基本的机器学习知识还是要整理一波 o inception 网络 xff1a 主要应用了深度可分离卷积 xff1a 主要用了大尺度
  • 面试可能遇到的问题野指针等解决方法

    空指针 xff1a 一般声明一个指针变量赋值为NULL xff0c 这就是空指针 xff0c 各个类型的空指针都存在确确实实的内存地址 xff0c 但是不会指向任何有效的值的内存地址 xff0c 对空指针操作 xff0c 例如访问属性和方法
  • 大规模分布式储存系统笔记(一)

    分布式储存系统的特性 xff1a 1 可扩展性 可按集群规模增长 xff0c 系统性能线性增长 xff1b 2 低成本 系统自动容错 xff0c 自动负载均衡 xff0c 运维方便 3 高性能 4 易用性 对外提供接口 数据类型 xff1a
  • 用MATLAB实现对运动物体识别与跟踪

    不得不说MATLAB的图像处理函数有点多 xff0c 但速度有时也是出奇的慢 还是想c的指针 xff0c 虽然有点危险 xff0c 但速度那是杠杠的 第二个MATLAB程序 xff0c 对运动物体的识别与追踪 这里我们主要运用帧差法实现运动
  • PS 开启GPU加速图片处理

    还认为你的电脑的速度效果比不上苹果吗 xff1f 还在嫌电脑渲染速度慢吗 xff1f 试一下 xff0c 电脑开启GPU硬件加速吧 xff01 只要有独显轻松加速 xff08 毕竟苹果笔记本要配独显电脑的价格基本上在15000以上 xff0
  • 管道鸟cortex-M4(TM4C1294)

    看到满屏的贪吃蛇 xff0c 我也来开源一个Ti开发板 xff08 TM4C1294 xff09 的游戏 将简化版的管道鸟 xff0c 根据自己玩的经历 xff0c 在cortexm4开发板上重新撸了一边 xff0c 设计思路 xff1a
  • C#连接MYSQL数据库并进行查询

    之前用MFC开发结果界面太难看被pass了 要求用C 重新来开发 gt lt 不过终于摆脱VC6 0的蛋疼操作了Y 先来连接数据库 xff08 1 xff09 用c 连接MYSQL数据库需要用到mysql connector net xff
  • binascii.Error: Incorrect padding 报错解决

    输入的base64编码字符串必须符合base64的padding规则 当原数据长度不是3的整数倍时 如果最后剩下两个输入数据 xff0c 在编码结果后加1个 61 xff1b 如果最后剩下一个输入数据 xff0c 编码结果后加2个 61 x
  • 通过过滤器链了解spring security + oauth2实现单点登录的过程

    一 系统 注意部署在同一机器 xff08 localhost xff09 上的三个应用 xff0c 为了防止存放在cookie中的JSESSIONID不被覆盖 xff0c 需要设置不同的path xff0c 可以在配置文件中指定不同的上下文
  • jetson tx2开箱上电

    期待已久的jetson tx2终于到了 xff0c 来做一个开箱 jetson tx2是英伟达的第三代GPU嵌入式开发板 前两代分别是jetson tk1和jetson tx1 jetson tk1 xff1a 绿色的版板子接口丰富 jet
  • Jetson tx2刷机过程中的坑

    暑假各种事忙得差不多后 xff0c 终于有时间拿出早就申请到的tx2 xff0c 开始刷机教程 xff0c 这两天几乎踩边了所有的坑 第一个坑 xff0c 虚拟机 一般在安装VMware虚拟机时 xff0c 建议的安装空间20GB xff0
  • python词云实现

    python的一个蛮酷炫的功能是可以轻松地实现词云 github上有关于这个项目的开源代码 xff1a https github com amueller word cloud 注意跑例程时要删除里面的wordcloud文件夹 词云的功能有
  • docker中accessTokens拉取私有git仓库

    背景 当需要git clone拉取私有库时 xff0c 传统的做法为将本机的ssh配置到gitlab中 但在docker中执行程序时需要拉取私有库 xff0c 此时无法为每个docker容器配置ssh 网上的一种方案为 xff0c 将配置好
  • Docker世界 -- 进阶篇(入门)

    一 Docker Compose 1 1 Docker Compose 介绍 1 1 1 简介 xff1a 传统的 docker 服务 xff0c 我们一般通过编写 Dockerfile 文件 xff0c 通过 build 命令创建一个镜像
  • 树莓派pico CMake工程 直接添加 .c .h文件

    假设工程名test1 xff0c 带main 的源代码文件 main c xff0c 要往工程里添加oled c oled h之类的源代码 直接添加为可执行文件 xff1a 编辑工程根目录的 CmakeLists txt add execu
  • 张量的通俗理解

    1 关于张量的四种定义 张量 在不同的运用场景下有不同的定义 xff08 1 xff09 张量是多维数组 xff0c 这个定义常见于各种人工智能软件 听起来还好理解 xff08 2 xff09 张量是某种几何对象 xff0c 不会随着坐标系
  • 如何搭建node_exporter

    如何搭建node exporter 1 观看条件 1 假设你已经看过上一篇文章 如何搭建普罗米修斯 Prometheus 2 假设你已经会搭建普罗米修斯 xff08 promethus xff09 3 上面两个假设 xff0c 只要满足一个
  • python类中初始化形式:def __init__(self)和def __init__(self, 参数1,参数2,···,参数n)区别

    前言 这两种初始化形式 xff0c 就类似于C 43 43 类中的构造函数 形式1 def init self span class token keyword class span span class token class name
  • Go语言操作grpc详细使用

    Go语言操作grpc详细使用 零 参考链接一 protobuf的详细使用二 grpc与protobuf的go文件的生成1 安装两个插件2 写proto文件3 编译proto文件 xff0c 生成go文件 三 grpc的详细使用1 一元RPC