Go中的gRPC入门详解

Go GRPC 入门

1,安装包

grpc

golang-grpc 包提供了 gRPC 相关的代码库,通过这个库我们可以创建 gRPC 服务或客户端,首先需要安装他。

go get -u google.golang.org/grpc

协议插件

要玩 gRPC,自然离不开 proto 文件,需要安装两个包,用于支持 protobuf 文件的处理。

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

注:GOPATH/bin 下有个 protoc-gen-go.exe 文件,然而这个只是 protoc 的插件,他本身不是 protoc 工具。。。

Protocol Buffers

Protocol Buffers 是一个与编程语言无关、与平台无关的可拓展机制,用于序列化结构数据,是一种数据交换格式,gRPC 使用 protoc 作为协议处理工具。

学习 Go 的 gRPC 时,有个坑,很多文章里面都没有说到要安装这个,执行命令提示不存在 protoc 命令。

首先到 https://github.com/protocolbuffers/protobuf/releases 下载 相应的包,例如笔者下载的是 protoc-3.15.6-win64.zip

解压后,复制里面的 bin\protoc.exe 文件,复制到 GOPATH\bin 命令,跟 protoc-gen-go.exe 放一起。

测试

以上都妥当后,我们在一个新的目录,创建一个 test.proto 文件,其内容示例如下如下:

注:protoc-3.15.6-win64\include\google\protobuf 目录也有很多示例。

syntax = "proto3";

// 包名
package  test;

// 指定输出 go 语言的源码到哪个目录以及文件名称
// 最终在 test.proto 目录生成 test.pb.go
// 也可以只填写 "./"
option go_package = "./;test";

// 如果要输出其它语言的话
// option csharp_package="MyTest";

service Tester{
  rpc MyTest(Request) returns (Response){}
}

// 函数参数
message  Request{
  string  jsonStr = 1;
}

// 函数返回值
message  Response{
  string  backJson = 1;
}

然后在 proto 所在目录,执行命令将 proto 转换为相应的编程语言文件。

protoc --go_out=plugins=grpc:. *.proto

会发现在当前目录输出了 test.pb.go 文件。

2,gRPC 服务端

创建一个 go 程序,把 test.pb.go 复制放到在 main.go 目录,在 main.go 引入 grpc:

import (
	"context"
	"fmt"
	"google.golang.org/grpc"
        // test.pb.go 默认包名是 package 为 main,不需要在这里引入
	"google.golang.org/grpc/reflection"
	"log"
	"net"
)

在 test.pb.go 中,生成了两个个 Tester 的接口,我们来看一下这两个接口的定义:

type TesterServer interface {
	MyTest(context.Context, *Request) (*Response, error)
}

type TesterClient interface {
	MyTest(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error)
}

要实现 proto 中的服务,则需要我们实现 TesterServer 接口,要编写 客户端,则需要实现 TesterClient 。

这里我们先实现 Server。

// 用于实现 Tester 服务
type MyGrpcServer struct{}

func (myserver *MyGrpcServer) MyTest(context context.Context, request *Request) (*Response, error) {
	fmt.Println("收到一个 grpc 请求,请求参数:", request)
	response := Response{BackJson: `{"Code":666}`}
	return &response, nil
}

接着我们创建 gRPC 服务。

func main() {
	// 创建 Tcp 连接
	listener, err := net.Listen("tcp", ":8028")
	if err != nil {
		log.Fatalf("监听失败: %v", err)
	}

	// 创建gRPC服务
	grpcServer := grpc.NewServer()

	// Tester 注册服务实现者
	// 此函数在 test.pb.go 中,自动生成
	RegisterTesterServer(grpcServer, &MyGrpcServer{})

	// 在 gRPC 服务上注册反射服务
	// func Register(s *grpc.Server)
	reflection.Register(grpcServer)

	err = grpcServer.Serve(listener)
	if err != nil {
		log.Fatalf("failed to serve: %v", err)
	}
}

3,gRPC 客户端

创建一个新的 go 项目,把 test.pb.go 复制放到 main.go 同级目录,main.go 的代码:

package main

import (
	"bufio"
	"context"
	"google.golang.org/grpc"
	"log"
	"os"
)

func main() {
	conn, err := grpc.Dial("127.0.0.1:8028", grpc.WithInsecure())
	if err != nil {
		log.Fatal("连接 gPRC 服务失败,", err)
	}

	defer conn.Close()

	// 创建 gRPC 客户端
	grpcClient := NewTesterClient(conn)

	// 创建请求参数
	request := Request{
		JsonStr: `{"Code":666}`,
	}

	reader := bufio.NewReader(os.Stdin)

	for {
		// 发送请求,调用 MyTest 接口
		response, err := grpcClient.MyTest(context.Background(), &request)
		if err != nil {
			log.Fatal("发送请求失败,原因是:", err)
		}
		log.Println(response)

		reader.ReadLine()
	}
}

4,编译运行

由于创建的时候,test.pb.go 使用的包名是 main,所以在编译时,需要把多个 go 文件一起编译:

go build .\main.go .\test.pb.go

然后分别启动 server 和 client,在 client 每按下一次回车键,便发送一次 gRPC 消息。

到这里,我们学习了一个完整的 gRPC 从创建协议到创建服务和客户端的过程,下面将接着学习一些相关的知识,了解一些细节。

5,其它

proto.Marshal 可以对请求的参数进行序列化,如:

	// 创建请求参数
	request := Request{
		JsonStr: `{"Code":666}`,
	}

	out,err:= proto.Marshal(&request)
	if err != nil {
		log.Fatalln("Failed to encode address book:", err)
	}
	if err := ioutil.WriteFile("E:/log.txt", out, 0644); err != nil {
		log.Fatalln("Failed to write address book:", err)
	}

而 proto.Unmarshal 则可以反序列化。

我们还可以自定义如何序列化反序列化消息,代码示例:

b, err := MarshalOptions{Deterministic: true}.Marshal(m)

GRPC

Protobuf buffer

Protobuf buffer 是一种数据格式,而 Protobuf 是 gRPC 协议,这里需要区分一下。

protobuf buffer 是 Google 用于序列化结构话数据的开源机制,要定义一个 protobuf buffer,需要使用 message 定义。

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

开源看到,每个字段都有一个 数字, = 1 这个不是赋值,而是编号。一个 message 中,每个字段都有唯一的编号,这些数字用于标识二进制格式的字段(数据传输时会被压缩等),当编号范围是 1-15 时,存储编号需要一个字节,也就是说 message 中的字段尽量不超过 15 个,1-15 编号用来定义频繁出现的消息元素。当然,也可以使用16-2047 之间的数字作为编号,此时存储编号需要两个字节。

详细的说可以参考官方文档:

https://developers.google.com/protocol-buffers/docs/overview

字段类型

字段类型就不详细列表了,读者可以参考官方文档,这里列一下常用的数据类型:

double、float、int32、int64、bool、string、bytes、枚举。

由于 gRPC 需要考虑兼容 C 语言、C#、Java、Go 语言等,所以 gRPC 中的类型不等同于编程语言中的相关类型。这些类型都是 gRPC 中定义的,并且如果要转换为编程语言中的类型,需要一些转换机制,而这有时会十分麻烦。

字段规则

每个字段都可以指定一个规则,在定义字段类型的开头使用规则标识。

有以下三种规则:

  • required:格式正确的消息必须恰好具有此字段之一,即必填字段。
  • optional:格式正确的消息可以包含零个或一个此字段(但不能超过一个,即值是可选的。
  • repeated:在格式正确的消息中,此字段可以重复任意次(包括零次),重复值的顺序将保留,表示该字段可以包含0~N个元素。

由于历史原因,repeated标量数字类型的字段编码效率不高。新代码应使用特殊选项[packed=true]来获得更有效的编码。例如:

repeated int32 samples = 4 [packed=true];

在可选字段中 optional 中,我们可以为其设置一个默认值,当传递消息时如果没有填写此字段,则使用其默认值:

optional int32 result_per_page = 3 [default = 10];

Protobuf

接下来将介绍 gRPC 的协议格式(protobuf),下面是官方文档的一个示例:

syntax = "proto3";
package tutorial;

import "google/protobuf/timestamp.proto";

syntax 指明协议的版本;

package 指明该 .proto 的名称;

import 关键字可以在当前 .proto 中引入其它 .proto 文件,gRPC 基本数据类型中不包含时间格式,可以引入 timestamp.proto

不同编程语言引入包/库的方式是不同的,C++ 和 C# 都是使用命名空间区分代码位置;Java 以目录、公共类严格区别包名;go 则是以一个 .go 文件任意设置 package 名称。

前面提到了 protoc,可以将协议文件转为为具体的代码。

为了兼容各种编程语言,我们协议设置 _package,这样可以支持生成不同语言代码时设置包/库名称。

例如 :

option go_package = "Test";					// ...
option csharp_package = "MyGrpc.Protos";	// 生成命名空间 namespace MyGrpc.Protos{}
option java_paclage = "MyJava.Protos";		// ...

gRPC 四种服务方法

protobuf 中除了可以定义 message,也可以定义流式接口。

gRPC使您可以定义四种服务方法:

  • 一元 RPC,客户端向服务器发送单个请求并获得单个响应,就像普通的函数调用一样。前面我们提到的都是一元 gRPC。

    rpc SayHello(HelloRequest) returns (HelloResponse);
    
  • 服务器流式RPC,客户端在其中向服务器发送请求,并获取流以读取回一系列消息。客户端从返回的流中读取,直到没有更多消息为止。gRPC保证在单个RPC调用中对消息进行排序。

    客户端 -> 服务端 -> 返回流 -> 客户端 -> 接收流

    rpc LotsOfReplies(HelloRequest) returns (stream HelloResponse);
    
  • 客户端流式RPC,客户端在其中编写消息序列,然后再次使用提供的流将其发送到服务器。客户端写完消息后,它将等待服务器读取消息并返回其响应。gRPC再次保证了在单个RPC调用中的消息顺序。

    客户端 -> 发送流 -> 服务端 -> 接收流 ->

    rpc LotsOfGreetings(stream HelloRequest) returns (HelloResponse);
    
  • 双向流式RPC,双方都使用读写流发送一系列消息。这两个流独立运行,因此客户端和服务器可以按照自己喜欢的顺序进行读写:例如,服务器可以在写响应之前等待接收所有客户端消息,或者可以先读取消息再写入消息,或读写的其他组合。每个流中的消息顺序都会保留。
    rpc BidiHello(stream HelloRequest) returns (stream HelloResponse);
    

编译 proto

前面我们用 protoc 来编译 .proto 文件为 go 语言,为了支持编译为 go,需要安装 protoc-gen-go 插件,C# 可以安装 protoc-gen-zsharp 插件。

需要注意的是,转换 .proto 为编程语言,不一定要安装 protoc。

例如 C# 只需要把 .proto 文件放到项目中,通过包管理器安装一个库,就会自动转换为相应的代码。

回归正题,聊一下 protoc 编译 .proto 文件的命令。

protoc 常用的参数如下:

 --proto_path=.		#指定proto文件的路径,填写 . 表示就在当前目录下
 --go_out=.			#表示编译后的文件存放路径;如果编译的是 csharp,则 --csharp_out
 --go_opt={xxx.proto}={xxx.proto的路径}
 # 示例:--go_opt=Mprotos/bar.proto=example.com/project/protos/foo

最简单的编译命令:

protoc --go_out=.  *.proto

--{xxx}_out 指令是必须的,因为要输出具体的编程语言代码。

这个输出文件的路径是执行命令的路径,如果我们不在 .proto 文件目录下执行命令,则输出的代码便不是相同位置了。为了解决这个问题,我们可以使用:

--go_opt=paths=source_relative

这样在别的地方执行命令,生成的代码会跟 .proto 文件放在相同的位置。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • 详解golang consul-grpc 服务注册与发现

    在微服务架构里面,每个小服务都是由很多节点组成,节点的添加删除故障希望能对下游透明,因此有必要引入一种服务的自动注册和发现机制,而 consul 提供了完整的解决方案,并且内置了对 GRPC 以及 HTTP 服务的支持 总体架构 服务调用: client 直连 server 调用服务 服务注册: 服务端将服务的信息注册到 consul 里 服务发现: 客户端从 consul 里发现服务信息,主要是服务的地址 健康检查: consul 检查服务器的健康状态 服务注册 服务端将服务信息注册到 con

  • go grpc安装使用教程

    gRPC是由Google主导开发的RPC框架,使用HTTP/2协议并用ProtoBuf作为序列化工具.其客户端提供Objective-C.Java接口,服务器侧则有Java.Golang.C++等接口,从而为移动端(iOS/Androi)到服务器端通讯提供了一种解决方案. 当然在当下的环境下,这种解决方案更热门的方式是RESTFull API接口.该方式需要自己去选择编码方式.服务器架构.自己搭建框架(JSON-RPC). 1. 前提 确保go的版本在1.6及以上 确保glibc版本在2.14及

  • golang使用grpc+go-kit模拟oauth认证的操作

    我们使用grpc对外的接口,进行服务,模拟对外认证的接口 首先我们要了解oauth的基本认证过程 第三方的服务端,在oauth2.0中作为一个客户端的身份,进行请求数据. 用户进行选择第三方的登陆,比如选择到某一个第三方的平台进行登陆,则会跳转到第三方登陆平台 用户输入用户名密码,在第三方平台进行登陆,,如果登陆成功,则返回code. 客户端,也就是我们想要登陆的网站,将会读取code,并且将会携带这个code,和第三方网站所颁发的密码,进行请求token,如果code和注册时所得到的密码,都验

  • golang在GRPC中设置client的超时时间

    超时 建立连接 主要就2函数Dail和DialContext. // Dial creates a client connection to the given target. func Dial(target string, opts ...DialOption) (*ClientConn, error) { return DialContext(context.Background(), target, opts...) } func DialContext(ctx context.Cont

  • golang grpc 负载均衡的方法

    微服务架构里面,每个服务都会有很多节点,如果流量分配不均匀,会造成资源的浪费,甚至将一些机器压垮,这个时候就需要负载均衡,最简单的一种策略就是轮询,顺序依次选择不同的节点访问. grpc 在客户端提供了负载均衡的实现,并提供了服务地址解析和更新的接口(默认提供了 DNS 域名解析的支持),方便不同服务的集成 使用示例 conn, err := grpc.Dial( "", grpc.WithInsecure(), // 负载均衡,使用 consul 作服务发现 grpc.WithBal

  • Golang实现gRPC的Proxy的原理解析

    背景 gRPC是Google开始的一个RPC服务框架, 是英文全名为Google Remote Procedure Call的简称. 广泛的应用在有RPC场景的业务系统中,一些架构中将gRPC请求都经过一个gRPC服务代理节点或网关,进行服务的权限现在,限流,服务调用简化,增加请求统计等等诸多功能. 如下以Golang和gRPC为例,解析gRPC的转发原理. gRPC Proxy原理 基本原理如下 基于TCP启动一个gRPC代理服务 拦截gRPC框架的服务映射,能将gRPC请求的服务拦截到转发代

  • golang 微服务之gRPC与Protobuf的使用

    RPC是什么? 所谓RPC(remote procedure call 远程过程调用)框架实际是提供了一套机制,使得应用程序之间可以进行通信,而且也遵从server/client模型.使用的时候客户端调用server端提供的接口就像是调用本地的函数一样. gRPC是什么? 与许多RPC系统一样,gRPC基于定义服务的思想,指定可以使用其参数和返回类型远程调用的方法.默认情况下,gRPC使用协议缓冲区作为接口定义语言(IDL)来描述服务接口和有效负载消息的结构. gRPC有什么好处以及在什么场景下

  • Go中的gRPC入门详解

    Go GRPC 入门 1,安装包 grpc golang-grpc 包提供了 gRPC 相关的代码库,通过这个库我们可以创建 gRPC 服务或客户端,首先需要安装他. go get -u google.golang.org/grpc 协议插件 要玩 gRPC,自然离不开 proto 文件,需要安装两个包,用于支持 protobuf 文件的处理. go get -u github.com/golang/protobuf go get -u github.com/golang/protobuf/pr

  • python二维码操作:对QRCode和MyQR入门详解

    python是所有编程语言中模块最丰富的 生活中常见的二维码功能在使用python第三方库来生成十分容易 三个大矩形是定位图案,用于标记二维码的大小.这三个定位图案有白边,通过这三个矩形就可以标识一个二维码了. QRCode 生成这个二维码只用一行 import qrcode qrcode.make("不睡觉干嘛呢").get_image().show() #设置URL必须添加http:// 安装导入QRCode pip install qrcode #方法多,体量小 安装导入MyQR

  • Python 数值区间处理_对interval 库的快速入门详解

    使用 Python 进行数据处理的时候,常常会遇到判断一个数是否在一个区间内的操作.我们可以使用 if else 进行判断,但是,既然使用了 Python,那我们当然是想找一下有没有现成的轮子可以用.事实上,我们可以是用 interval 这一个库来完成我们需要的操作. 区间判断基础 最基础的区间判断操作就是先创建一个区间几个,然后使用 in 来判断一个数是否存在于区间之内.代码如下: from interval import Interval zoom_2_5 = Interval(2, 5)

  • C语言文件操作的入门详解教程

    一.一些需要掌握的知识点 文件有千千万万,但是在我们的程序设计当中,我们谈的文件一般有两种: 1.程序文件 包括源程序文件(后缀为.c),目标文件(windows环境后缀为.obj),可执行程序(windows环境后缀为.exe). 2.数据文件 文件的内容不一定是程序,而是程序运行时读写的数据,比如程序运行需要从中读取数据的文件,或者输出内容的文件. 而在本节中,我们主要提到的是数据文件. 1.文件名 我们知道,名字都是用来标识和区别事物的,那么文件名也是这样,是区别各个文件的标识. 一个文件

  • SpringBoot快速入门详解

    Spring Boot是什么? Spring Boot并不是什么新的框架,它是对Spring的缺点进行了改善和优化,Spring Boot默认了很多的框架使用方式,像maven整合了所以jar包同一个道理.及SpringBoot并不是对Spring功能上的增强,而是提供了一种快速使用Spring的方式而已. 为什么使用Spring Boot? Spring Boot官方是这么说的:Spring Boot它是基于Spring开发项目的起点,Spring Boot的设计主要是让你快速地跑起来Spri

  • Java SpringBoot模板引擎之 Thymeleaf入门详解

    目录 模板引擎简介 引入Thymeleaf模板引擎 分析Thymeleaf模板引擎 测试Thymeleaf模板引擎 1.编写一个TestController 2.编写一个测试页面 test.html 放在 templates 目录下 3.启动项目请求测试 4.结论 Thymeleaf入门: 1.修改测试请求,增加数据传输 2.使用thymeleaf 3.我们去编写下前端页面 4.启动测试! thymeleaf语法学习 1.使用任意的 th:attr 来替换Html中原生属性的值! 2.表达式语法

  • C++元编程语言初步入门详解

    目录 模板 泛型初步 函数模板 友元 模板参数 元编程的基本概念 可变参数模板 模板 由于模板元编程需要以面向对象为基础,所以如有疑问之处可以先补充一点C++面向对象的知识: C++面向对象这一篇就够了 泛型初步 由于C++是静态强类型语言,所以变量一经创建,则类型不得更改.如果我们希望创建一种应用广泛地复数类型,那么相应地需要基于int.float.double这些基础类型逐一创建,十分麻烦.泛型编程便是为了简化这一过程而生. 能够容纳不同数据类型作为成员的类被成为模板类,其基本方法为在类声明

  • Java+TestNG接口自动化入门详解

    目录 一.环境准备:(根据自己电脑配置来选择安装版本,我的电脑是64位,所以此处选择64位安装) 二.环境安装: 三.TestNG接口自动化实现 四.创建自己的第一个接口自动化脚本 五.批量执行自动化脚本 六.生成并查看自动化测试报告 一.环境准备:(根据自己电脑配置来选择安装版本,我的电脑是64位,所以此处选择64位安装) JDK下载: JDK 1.8下载地址: http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downl

  • vite.config.js配置入门详解

    目录 1 如何创建vite项目? 2 如何让vite项目启动时自动打开浏览器? 3vite启动默认端口为3000?如何更改默认端口? 4 vite如何设置热更新? 5vite中如何配置别名路径? 6 vite中如何设置便捷图片路径引用? 7如何把vite打包以后的js,css和img资源分别分门别类在js/css/img文件夹中? 8 如何通过vite给项目配置多个环境? 9 vite中如何配置多入口,进行多页面开发? 10 如何设置开启生产打包分析文件大小功能?类似webpack-bundle

  • python库h5py入门详解

    目录 h5py简单介绍 1.创建一个h5py文件 2.创建dataset数据集 3.创建group组 本文只是简单的对h5py库的基本创建文件,数据集和读取数据的方式进行介绍,作者刚接触h5py,完全靠看文档自学,如果哪里说的不对,欢迎纠正!如果读者需要进一步详细的学习h5py的更多知识,请参考h5py的官方文档. h5py简单介绍 h5py文件是存放两类对象的容器,数据集(dataset)和组(group),dataset类似数组类的数据集合,和numpy的数组差不多.group是像文件夹一样

随机推荐