简介
gRPC 是一个高性能、开源和通用的 RPC 框架,面向移动和 HTTP/2 设计。目前提供 C、Java 和 Go 语言版本,分别是:grpc, grpc-java, grpc-go. 其中 C 版本支持 C, C++, Node.js, Python, Ruby, Objective-C, PHP 和 C# 支持.
gRPC 基于 HTTP/2 标准设计,带来诸如双向流、流控、头部压缩、单 TCP 连接上的多复用请求等特。这些特性使得其在移动设备上表现更好,更省电和节省空间占用
在 gRPC 里客户端应用可以像调用本地对象一样直接调用另一台不同的机器上服务端应用的方法,使得您能够更容易地创建分布式应用和服务。与许多 RPC 系统类似,gRPC 也是基于以下理念:定义一个服务,指定其能够被远程调用的方法(包含参数和返回类型)。在服务端实现这个接口,并运行一个 gRPC 服务器来处理客户端调用。在客户端拥有一个存根能够像服务端一样的方法。

gRPC 客户端和服务端可以在多种环境中运行和交互 - 从 google 内部的服务器到你自己的笔记本,并且可以用任何 gRPC 支持的语言来编写。所以,你可以很容易地用 Java 创建一个 gRPC 服务端,用 Go、Python、Ruby 来创建客户端。此外,Google 最新 API 将有 gRPC 版本的接口,使你很容易地将 Google 的功能集成到你的应用里。
gRPC 基础:Go
本教程提供了 Go 程序员如何使用 gRPC 的指南。
- 在一个 .proto 文件内定义服务。
- 用 protocol buffer 编译器生成服务器和客户端代码。
- 使用 gRPC 的 Go API 为你的服务实现一个简单的客户端和服务器。
安装gRPC
创建一个空项目,使用go module的方式,Go版本:1.13,
go get -u google.golang.org/grpc
使用 protocol buffers
Google Protocol Buffer( 简称 Protobuf)轻便高效的序列化数据结构的协议,可以用于网络通信和数据存储。
特点:性能高、传输快、维护方便,
一些第三方rpc库都会支持protobuf
安装 Protobuf编译器
https://github.com/protocolbuffers/protobuf/releases/latest
这是protobuf编译器,将.proto文件,转译成protobuf的原生数据结构
找到对应操作系统的zip解压 ,把bin目录加入环境变量
Protobuf github地址:
https://github.com/protocolbuffers/protobuf
golang库所属地址
https://github.com/golang/protobuf
protobuf相关文档
https://developers.google.com/protocol-buffers/docs/gotutorial
安装go Protobuf插件
go get github.com/golang/protobuf/protoc-gen-go
此时会在你的GOPATH 的bin目录下生成可执行文件. protobuf的编译器插件protoc-gen-go
等下我们执行protoc 命令时 就会自动调用这个插件
服务端目录说明
├── services
│ ├── ProdService.go
│ ├── Prod.pb.go
├── pbfiles
│ ├── Prod.proto
|── server.go
定义服务
官方文档里的说明
service RouteGuide {
...
}
-
一个 简单 RPC , 客户端使用存根发送请求到服务器并等待响应返回,就像平常的函数调用一样。
然后在你的服务中定义 rpc 方法,指定请求的和响应类型。gRPC 允许你定义4种类型的 service 方法,这些都在 RouteGuide 服务中使用:rpc GetFeature(Point) returns (Feature) {}
-
一个 服务器端流式 RPC , 客户端发送请求到服务器,拿到一个流去读取返回的消息序列。 客户端读取返回的流,直到里面没有任何消息。从例子中可以看出,通过在 响应 类型前插入 stream 关键字,可以指定一个服务器端的流方法。
rpc ListFeatures(Rectangle) returns (stream Feature) {} -
一个 客户端流式 RPC , 客户端写入一个消息序列并将其发送到服务器,同样也是使用流。一旦客户端完成写入消息,它等待服务器完成读取返回它的响应。通过在 请求 类型前指定 stream 关键字来指定一个客户端的流方法。
rpc RecordRoute(stream Point) returns (RouteSummary) {}
-
一个 双向流式 RPC 是双方使用读写流去发送一个消息序列。两个流独立操作,因此客户端和服务器可以以任意喜欢的顺序读写:比如, 服务器可以在写入响应前等待接收所有的客户端消息,或者可以交替的读取和写入消息,或者其他读写的组合。 每个流中的消息顺序被预留。你可以通过在请求和响应前加 stream 关键字去制定方法的类型。
rpc RouteChat(stream RouteNote) returns (stream RouteNote) {}
-
我们的 .proto 文件也包含了所有请求的 protocol buffer 消息类型定义以及在服务方法中使用的响
应类型——比如,下面的Point消息类型:message Point { int32 latitude = 1; int32 longitude = 2; }
定义商品中间文件Prod.proto
syntax="proto3";
package services;
message ProdRequest{
int32 prod_id = 1;
ProdAreas ProdArea = 2;
}
enum ProdAreas{
A=1;
B=2;
C=3;
}
message ProdResponse{
int32 prod_stock=1;//商品库存
}
service ProdService {
rpc GetProdStock (ProdRequest) returns (ProdResponse);
}
生成go文件
protoc --go_out=plugins=grpc:../services Prod.proto
服务端实现Prod.proto 中的GetProdStock 方法
ProdService.go
import (
"context"
)
type ProdService struct {}
func (this *ProdService)GetProdStock(ctx context.Context,request *ProdRequest) (*ProdResponse, error) {
var stock int32 = 0
if request.ProdArea == 0{
stock = 30
}else if request.ProdArea == ProdAreas_A{
stock = 31
}else if request.ProdArea == ProdAreas_B{
stock = 40
}else if request.ProdArea == ProdAreas_C{
stock = 50
}
return &ProdResponse{ProdStock:stock},nil
}
服务端创建RPC服务
server.go
package main
import (
"google.golang.org/grpc"
"services"
"net"
)
func main() {
rpcServer:=grpc.NewServer()
services.RegisterProdServiceServer(rpcServer,new(services.ProdService))
lis,_:=net.Listen("tcp",":8081")
rpcServer.Serve(lis)
}
客户端拷贝 Prod.pb.go
├── services
│ ├── Prod.pb.go
├── client.go
client.go
package main
import (
"context"
"fmt"
"google.golang.org/grpc"
"services"
"log"
)
func main(){
conn,err:=grpc.Dial(":8081",grpc.WithInsecure())
if err!=nil{
log.Fatal(err)
}
defer conn.Close()
prodClient:=services.NewProdServiceClient(conn)
prodRes,err:=prodClient.GetProdStock(context.Background(),
&services.ProdRequest{ProdId: 101,ProdArea: services.ProdAreas_A})
if err!=nil{
log.Fatal(err)
}
fmt.Println(prodRes)//prod_stock:31
}
网友评论