protobuffer、gRPC、restful gRPC的相互转化
转自:https://studygolang.com/articles/12510
文档
protobuf
Google Protocol Buffer(简称 Protobuf)是一种轻便高效的结构化数据存储格式,平台无关、语言无关、可扩展,可用于通讯协议和数据存储等领域。
优点
- 平台无关,语言无关,可扩展;
- 提供了友好的动态库,使用简单;
- 解析速度快,比对应的XML快约20-100倍;
- 序列化数据非常简洁、紧凑,与XML相比,其序列化之后的数据量约为1/3到1/10。
安装
https://github.com/google/protobuf/releases // 下载并编译、安装
go get github.com/golang/protobuf/proto // golang的protobuf库文件 // 插件
go get github.com/golang/protobuf/protoc-gen-go // 用于根据protobuf生成golang代码,语法 protoc --go_out=. *.proto
语法
book/book.proto
syntax="proto3";
package book; // import "xxx/xx.proto" // 出版社
message Publisher{
required string name =
}
// 书籍信息
message Book {
required string name = ;
message Author {
required string name = ;
required string address = ;
}
required Author author = ; enum BookType{
SCIENCE = ;
LITERATURE = ;
} optional BookType type = ;
optional Publisher publisher =
}
- syntax="proto3":指定protobuf的版本
- package book:声明一个报名,一般与文件目录名相同
- import "xxx/xx.proto":导入其他的包,这样你就可以使用其他的包的数据结构
- required、optional、repeated:表示该字段是否必须填充;required表示必须指定且只能指定一个;当optional表示可选,可指定也可不指定,但不可超过一个不指定值的时候会采用空值,如string类型的字段会用字符串表示;repeated表示可以重复,类似与编程语言中的list
- message Author:在一个message体内定义一个message结构体
- enum:是枚举类型结构体
- 数字:字段的标识符,不可重复
- 数据类型: int32、int64、uint32、uint64、sint32、sint64、double、float、 string、bool、bytes、enum、message等等
在golang使用
protobuf采用以上的book.proto文件
并使用以下命令生成go文件
protoc --go_out=. *.proto
在代码中使用
package main import (
b "book"
"github.com/golang/protobuf/proto"
) func main(){
...
// 将实例转为proto编码
var b = &b.Book{Name:"xxx", Author:b.Author{Name:"yyy"}}
protoBook, err := proto.Marshal(b)
...
// 讲proto编码转化为实例
var b2 b.Book
err = proto.Unmarshal(protoBook, &b2)
...
}
grpc
gRPC是由Google主导开发的RPC框架,使用HTTP/2协议并用ProtoBuf作为序列化工具。其客户端提供Objective-C、Java接口,服务器侧则有Java、Golang、C++等接口。使用grpc可以方便的调用其他进程的方法,调用需要传输的数据使用的是proto编码。这对于大型项目来说,可以有效的提高数据的解编码效率和数据传输率。
proto service定义
一个RPC service就是一个能够通过参数和返回值进行远程调用的method,我们可以简单地将它理解成一个函数。因为gRPC是通过将数据编码成protocal buffer来实现传输的。因此,我们通过protocal buffers interface definitioin language(IDL)来定义service method,同时将参数和返回值也定义成protocal buffer message类型。具体实现如下所示,包含下面代码的文件叫helloworld.proto:
syntax = "proto3"; package helloworld; // The greeter service definition.
service Greeter {
// Sends a greeting
rpc SayHello (HelloRequest) returns (HelloReply) {}
} // The request message containing the user's name.
message HelloRequest {
string name = ;
} // The response message containing the greetings
message HelloReply {
string message = ;
}
接着,根据上述定义的service,我们可以利用protocal buffer compiler ,即protoc生成相应的服务器端和客户端的GoLang代码。生成的代码中包含了客户端能够进行RPC的方法以及服务器端需要进行实现的接口。
假设现在所在的目录是$GOPATH/src/helloworld/helloworld,我们将通过如下命令生成gRPC对应的GoLang代码:
protoc --go_out=plugins=grpc:. helloworld.proto
此时,将在目录下生成helloworld.pb.go文件
server
server.go
package main // server.go import (
"log"
"net" "golang.org/x/net/context"
"google.golang.org/grpc"
pb "helloworld/helloworld"
) const (
port = ":50051"
) type server struct {} // 当接收到请求的时候回调用该方法
// 参数由grpc自己根据请求进行构造
func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
return &pb.HelloReply{Message: "Hello " + in.Name}, nil
} func main() {
lis, err := net.Listen("tcp", port)
if err != nil {
log.Fatal("failed to listen: %v", err)
}
s := grpc.NewServer()
pb.RegisterGreeterServer(s, &server{})
s.Serve(lis)
}
其中pb是我们刚才根据proto生成的go文件的包
client
package main //client.go import (
"log"
"os" "golang.org/x/net/context"
"google.golang.org/grpc"
pb "helloworld/helloworld"
) const (
address = "localhost:50051"
defaultName = "world"
) func main() {
// 建立一个grpc连接
conn, err := grpc.Dial(address, grpc.WithInsecure())
if err != nil {
log.Fatal("did not connect: %v", err)
}
defer conn.Close()
// 新建一个客户端,方法为:NewXXXClinent(conn),XXX为你在proto定义的服务的名字
c := pb.NewGreeterClient(conn) name := defaultName
if len(os.Args) > {
name = os.Args[]
}
// 调用远程,并得到返回
r, err := c.SayHello(context.Background(), &pb.HelloRequest{Name: name})
if err != nil {
log.Fatal("could not greet: %v", err)
}
log.Printf("Greeting: %s", r.Message)
}
restful转grpc
使用grpc的优点很多,二进制的数据可以加快传输速度,基于http2的多路复用可以减少服务之间的连接次数,和函数一样的调用方式也有效的提升了开发效率。不过使用grpc也会面临一个问题,我们的微服务对外一定是要提供Restful接口的,如果内部调用使用grpc,在某些情况下要同时提供一个功能的两套API接口,这样就不仅降低了开发效率,也增加了调试的复杂度。于是就想着有没有一个转换机制,让Restful和gprc可以相互转化。
grpc-gateway应运而生
安装
首先你得要根据本文之前的步骤安装proto和grpc,然后如下安装一些库
go get -u github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway
go get -u github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger
go get -u github.com/golang/protobuf/protoc-gen-go
用法
定义service的proto文件
syntax = "proto3";
package example; import "google/api/annotations.proto"; message StringMessage {
string value = ;
} service YourService {
rpc Echo(StringMessage) returns (StringMessage) {
option (google.api.http) = {
post: "/v1/example/echo"
body: "*"
};
}
}
option 表示处理哪些path的请求以及如何处理请求体(参数),见https://cloud.google.com/serv...
生成go文件
protoc -I/usr/local/include -I. \
-I$GOPATH/src \
-I$GOPATH/src/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis \
--go_out=plugins=grpc:. \
path/to/your_service.proto protoc -I/usr/local/include -I. \
-I$GOPATH/src \
-I$GOPATH/src/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis \
--grpc-gateway_out=logtostderr=true:. \
path/to/your_service.proto
以上生成的两个文件,第一个是pb.go文件,给grpc server用的;第二个是pb.gw.go文件,给grpc-gateway用的,用于grpc和restful的相互转化
服务器
package main import (
"flag"
"net/http" "github.com/golang/glog"
"golang.org/x/net/context"
"github.com/grpc-ecosystem/grpc-gateway/runtime"
"google.golang.org/grpc" gw "path/to/your_service_package"
) var (
echoEndpoint = flag.String("echo_endpoint", "localhost:9090", "endpoint of YourService")
) func run() error {
ctx := context.Background()
ctx, cancel := context.WithCancel(ctx)
defer cancel() mux := runtime.NewServeMux()
opts := []grpc.DialOption{grpc.WithInsecure()}
err := gw.RegisterYourServiceHandlerFromEndpoint(ctx, mux, *echoEndpoint, opts)
if err != nil {
return err
} return http.ListenAndServe(":8080", mux)
} func main() {
flag.Parse()
defer glog.Flush() if err := run(); err != nil {
glog.Fatal(err)
}
}
测试
curl -X POST -k http://localhost:8080/v1/example/echo -d '{"name": " world"} {"message":"Hello world"}
流程如下:curl用post向gateway发送请求,gateway作为proxy将请求转化一下通过grpc转发给greeter_server,greeter_server通过grpc返回结果,gateway收到结果后,转化成json返回给前端。
Grpc+Grpc Gateway实践
https://segmentfault.com/a/1190000013339403
假定我们有一个项目需求,希望用Rpc
作为内部API
的通讯,同时也想对外提供Restful Api
,写两套又太繁琐不符合
于是我们想到了Grpc
以及Grpc Gateway
,这就是我们所需要的
介绍与环境安装
准备环节
在正式开始我们的Grpc
+Grpc Gateway
实践前,我们需要先配置好我们的开发环境
- Grpc
- Protoc Plugin
- Protocol Buffers
- Grpc-gateway
Grpc
是什么
Google对Grpc
的定义:
A high performance, open-source universal RPC framework
也就是Grpc
是一个高性能、开源的通用RPC框架,具有以下特性:
- 强大的
IDL
,使用Protocol Buffers
作为数据交换的格式,支持v2
、v3
(推荐v3
) - 跨语言、跨平台,也就是
Grpc
支持多种平台和语言 - 支持HTTP2,双向传输、多路复用、认证等
安装
1、官方推荐(需科学上网)
go get -u google.golang.org/grpc
2、通过github.com
进入到第一个$GOTPATH目录(因为go get
会默认安装在第一个下)下,新建google.golang.org
目录,拉取golang
在github
上的镜像库:
cd /usr/local/go/path/src mkdir google.golang.org cd google.golang.org/ git clone https://github.com/grpc/grpc-go mv grpc-go/ grpc/
目录结构:
google.golang.org/
└── grpc
...
而在grpc
下有许多常用的包,例如:
- metadata:定义了
grpc
所支持的元数据结构,包中方法可以对MD
进行获取和处理 - credentials:实现了
grpc
所支持的各种认证凭据,封装了客户端对服务端进行身份验证所需要的所有状态,并做出各种断言 - codes:定义了
grpc
使用的标准错误码,可通用
Protoc Plugin
是什么
编译器插件
安装
go get -u github.com/golang/protobuf/protoc-gen-go
将Protoc Plugin
的可执行文件从$GOPATH中移动到$GOBIN下
mv /usr/local/go/path/bin/protoc-gen-go /usr/local/go/bin/
Protocol Buffers v3
是什么
Protocol buffers are a flexible, efficient, automated mechanism for serializing structured data – think XML, but smaller, faster, and simpler. You define how you want your data to be structured once, then you can use special generated source code to easily write and read your structured data to and from a variety of data streams and using a variety of languages. You can even update your data structure without breaking deployed programs that are compiled against the "old" format.
Protocol Buffers
是Google
推出的一种数据描述语言,支持多语言、多平台,它是一种二进制的格式,总得来说就是更小、更快、更简单、更灵活,目前分别有v2
、v3
的版本,我们推荐使用v3
建议可以阅读下官方文档的介绍,本系列会在使用时简单介绍所涉及的内容
安装
wget https://github.com/google/protobuf/releases/download/v3.5.1/protobuf-all-3.5.1.zip
unzip protobuf-all-3.5..zip
cd protobuf-3.5./
./configure
make
make install
检查是否安装成功
protoc --version
如果出现报错
protoc: error while loading shared libraries: libprotobuf.so.: cannot open shared object file: No such fileor directory
则执行ldconfig
后,再次运行即可成功
为什么要执行ldconfig
我们通过控制台输出的信息可以知道,Protocol Buffers Libraries
的默认安装路径在/usr/local/lib
Libraries have been installed in:
/usr/local/lib If you ever happen to want to link against installed libraries
in a given directory, LIBDIR, you must either use libtool, and
specify the full pathname of the library, or use the `-LLIBDIR'
flag during linking and do at least one of the following:
- add LIBDIR to the `LD_LIBRARY_PATH' environment variable
during execution
- add LIBDIR to the `LD_RUN_PATH' environment variable
during linking
- use the `-Wl,-rpath -Wl,LIBDIR' linker flag
- have your system administrator add LIBDIR to `/etc/ld.so.conf' See any operating system documentation about shared libraries for
more information, such as the ld() and ld.so() manual pages.
而我们安装了一个新的动态链接库,ldconfig
一般在系统启动时运行,所以现在会找不到这个lib
,因此我们要手动执行ldconfig
,让动态链接库为系统所共享,它是一个动态链接库管理命令,这就是ldconfig
命令的作用
protoc使用
我们按照惯例执行protoc --help
(查看帮助文档),我们抽出几个常用的命令进行讲解
1、-IPATH, --proto_path=PATH
:指定import
搜索的目录,可指定多个,如果不指定则默认当前工作目录
2、--go_out
:生成golang
源文件
参数
若要将额外的参数传递给插件,可使用从输出目录中分离出来的逗号分隔的参数列表:
protoc --go_out=plugins=grpc,import_path=mypackage:. *.proto
import_prefix=xxx
:将指定前缀添加到所有import
路径的开头import_path=foo/bar
:如果文件没有声明go_package
,则用作包。如果它包含斜杠,那么最右边的斜杠将被忽略。plugins=plugin1+plugin2
:指定要加载的子插件列表(我们所下载的repo中唯一的插件是grpc)Mfoo/bar.proto=quux/shme
:M
参数,指定.proto
文件编译后的包名(foo/bar.proto
编译后为包名为quux/shme
)
Grpc支持
如果proto
文件指定了RPC
服务,protoc-gen-go
可以生成与grpc
相兼容的代码,我们仅需要将plugins=grpc
参数传递给--go_out
,就可以达到这个目的
protoc --go_out=plugins=grpc:. *.proto
Grpc-gateway
是什么
grpc-gateway is a plugin of protoc. It reads gRPC service definition, and generates a reverse-proxy server which translates a RESTful JSON API into gRPC. This server is generated according to custom options in your gRPC definition.
grpc-gateway是protoc的一个插件。它读取gRPC服务定义,并生成一个反向代理服务器,将RESTful JSON API转换为gRPC。此服务器是根据gRPC定义中的自定义选项生成的。
安装
go get -u github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway
如果出现以下报错,我们分析错误提示可得知是连接超时(大概是被墙了)
package google.golang.org/genproto/googleapis/api/annotations: unrecognized import path "google.golang.org/genproto/googleapis/api/annotations" (https fetch: Get https://google.golang.org/genproto/googleapis/api/annotations?go-get=1: dial tcp 216.239.37.1:443: getsockopt: connection timed out)
有两种解决方法,
1、科学上网
2、通过github.com
进入到第一个$GOPATH目录的google.golang.org
目录下,拉取genproto
在github
上的go-genproto
镜像库:
cd /usr/local/go/path/src/google.golang.org git clone https://github.com/google/go-genproto.git mv go-genproto/ genproto/
在安装完毕后,我们将grpc-gateway
的可执行文件从$GOPATH中移动到$GOBIN
mv /usr/local/go/path/bin/protoc-gen-grpc-gateway /usr/local/go/bin/
到这里我们这节就基本完成了,建议多反复看几遍加深对各个组件的理解!
参考
示例代码
protobuffer、gRPC、restful gRPC的相互转化的更多相关文章
- Go gRPC进阶-gRPC转换HTTP(十)
前言 我们通常把RPC用作内部通信,而使用Restful Api进行外部通信.为了避免写两套应用,我们使用grpc-gateway把gRPC转成HTTP.服务接收到HTTP请求后,grpc-gatew ...
- 带入gRPC:gRPC Streaming, Client and Server
带入gRPC:gRPC Streaming, Client and Server 原文地址:带入gRPC:gRPC Streaming, Client and Server 前言 本章节将介绍 gRP ...
- 带入gRPC:gRPC Deadlines
带入gRPC:gRPC Deadlines 原文地址:带入gRPC:gRPC Deadlines项目地址:https://github.com/EDDYCJY/go... 前言 在前面的章节中,已经介 ...
- gRPC Motivation and Design Principles | gRPC https://grpc.io/blog/principles/
gRPC Motivation and Design Principles | gRPC https://grpc.io/blog/principles/
- grpc(二)记一次grpc debug--io.grpc.StatusRuntimeException: UNKNOWN
1.起初是dingding一直报错: instance:服务器名 err:GrpcClient#placeOrder: io.grpc.StatusRuntimeException: UNKNOWN ...
- grpc:gRPC Concepts
本文介绍一些主要的gRPC概念. 服务定义 gRPC支持4种方法: 1.Unary RPCs where the client sends a single request to the server ...
- gRPC helloworld service, RESTful JSON API gateway and swagger UI
概述 本篇博文完整讲述了如果通过 protocol buffers 定义并启动一个 gRPC 服务,然后在 gRPC 服务上提供一个 RESTful JSON API 的反向代理 gateway,最后 ...
- grpc,protoc, protoc-gen-go,rust
Rust 与服务端编程的碎碎念https://zhuanlan.zhihu.com/p/30028047 GRPC:golang使用protobuf https://segmentfault.com/ ...
- grpc-gateway:grpc对外提供http服务的解决方案
我所在公司的项目是采用基于Restful的微服务架构,随着微服务之间的沟通越来越频繁,就希望可以做成用rpc来做内部的通讯,对外依然用Restful.于是就想到了google的grpc. 使用grpc ...
随机推荐
- Android studio ButterKnife插件
1.功能:给所有的有id的控件添加注解 2.github地址 https://github.com/avast/android-butterknife-zelezny 3.插件下载地址 http:// ...
- Python多线程与多线程中join()的用法
多线程实例 https://www.cnblogs.com/cnkai/p/7504980.html 知识点一:当一个进程启动之后,会默认产生一个主线程,因为线程是程序执行流的最小单元,当设置多线程时 ...
- windowsclient开发--为你的client进行国际化
之前博客讲过函数: GetUserDefaultUILanguage Returns the language identifier for the user UI language for the ...
- 【iCore3应用】基于iCore3双核心板的编码器应用实例
简介 本硬件电路方案是针对集电极开路输出的编码器设计的.隔离前电压为5V,同时5V也是编码器的驱动电压,由外部供电:隔离后电压为3.3V,由核心板提供.隔离芯片采用3通道ADUM1300隔离芯片.因为 ...
- 学习Mysql过程中拓展的其他技术栈:Docker入门介绍
一.Docker的介绍和安装 1. Docker是什么 百度百科的介绍: Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linu ...
- 在IDEA中将项目部署到Tomcat的方法及两种模式的区别
转自:https://www.jianshu.com/p/fb0ed26c35d5 1.添加tomcat服务器 点右上角编辑配置 编辑配置 点击左上角+选择tomcat服务器 添加tomcat ...
- 【Math】根据置信度、样本数相关推导过程
时间长了会忘,备忘下. http://blog.csdn.net/liangzuojiayi/article/details/78044780 http://wiki.mbalib.com/wiki/ ...
- js中的原型继承
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- C#设计模式--观察者模式(发布-订阅模式)
0.C#设计模式--简单工厂模式 1.C#设计模式--工厂方法模式 2.C#设计模式--抽象工厂模式 3.C#设计模式--单例模式 4.C#设计模式--建造者模式 5.C#设计模式--原型模式 6.C ...
- iOS - 高德地图将地图的多点连线
@property (nonatomic, strong) MAPolyline *commonPoly; #pragma mark -- 将地图的点连线 - (void)createBrokenLi ...