-
Notifications
You must be signed in to change notification settings - Fork 3
grpc
cym edited this page Nov 26, 2017
·
1 revision
gRPC 是一个高性能、开源、通用的RPC框架,由Google推出,基于HTTP/2协议标准设计开发,默认采用Protocol Buffers数据序列化协议,支持多种开发语言。gRPC提供了一种简单的方法来精确的定义服务,并且为客户端和服务端自动生成可靠的功能库。
在 Mac 下:
$ brew tap grpc/grpc
$ brew install --with-plugins grpc
$ go get -u github.com/golang/protobuf/{proto,protoc-gen-go}
$ go get -u google.golang.org/grpc
使用protoc命令编译.proto文件,不同语言支持需要指定输出参数,如:
protoc --proto_path=IMPORT_PATH --cpp_out=DST_DIR --java_out=DST_DIR --python_out=DST_DIR --go_out=DST_DIR --ruby_out=DST_DIR --javanano_out=DST_DIR --objc_out=DST_DIR --csharp_out=DST_DIR path/to/file.proto
-
-I
参数:指定 import 路径,可以指定多个-I
参数,编译时按顺序查找,不指定时默认查找当前目录-
--go_out
:golang 编译支持,支持以下参数-
plugins=plugin1+plugin2
- 指定插件,目前只支持grpc,即:plugins=grpc
-
M
参数 - 指定导入的.proto
文件路径编译后对应的golang包名(不指定本参数默认就是.proto
文件中import语句的路径) -
import_prefix=xxx
- 为所有import路径添加前缀,主要用于编译子目录内的多个proto文件,这个参数按理说很有用,尤其适用替代一些情况时的M参数,但是实际使用时有个蛋疼的问题导致并不能达到我们预想的效果,自己尝试看看吧 -
import_path=foo/bar
- 用于指定未声明package
或go_package
的文件的包名,最右面的斜线前的字符会被忽略 - 末尾
:[编译文件路径] xxx.proto(文件路径(支持通配符))
-
-
完整示例:
protoc -I . --go_out=plugins=grpc,Mfoo/bar.proto=bar,import_prefix=foo/,import_path=foo/bar:. ./*.proto
定义了一个Hello Service,客户端发送包含字符串名字的请求,服务端返回Hello消息。
- 编写.proto描述文件
- 编译生成.pb.go文件
- 服务端实现约定的接口并提供服务
- 客户端按照约定调用方法请求服务
syntax = "proto3"; // 指定proto版本
package proto; // 指定包名
// 定义Hello服务
service Hello {
// 定义SayHello方法
rpc SayHello(HelloRequest) returns (HelloReply) {}
}
// HelloRequest 请求结构
message HelloRequest {
string name = 1;
}
// HelloReply 响应结构
message HelloReply {
string message = 1;
}
hello.proto
文件中定义了一个Hello Service
,该服务包含一个SayHello
方法,同时声明了HelloRequest
和HelloReply
消息结构用于请求和响应。客户端使用HelloRequest
参数调用SayHello
方法请求服务端,服务端响应HelloReply
消息。
# 编译hello.proto
$ protoc -I . --go_out=plugins=grpc:. ./hello.proto
生成的.pb.go
文件,按照.proto
文件中的说明,包含服务端接口HelloServer
描述,客户端接口及实现HelloClient
,及HelloRequest
、HelloResponse
结构体,不要手动编辑该文件。
package main
import (
"net"
"log"
pb "projects/grpcExample/proto" // 引入编译生成的包
"golang.org/x/net/context"
"google.golang.org/grpc"
"google.golang.org/grpc/reflection"
)
const (
// Address gRPC服务地址
Address = "127.0.0.1:50052"
)
// 定义helloService并实现约定的接口
type helloService struct{}
// HelloService ...
var HelloService = helloService{}
func (h helloService) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
resp := new(pb.HelloReply)
resp.Message = "Hello " + in.Name + "."
return resp, nil
}
func main() {
lis, err := net.Listen("tcp", Address)
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
s := grpc.NewServer()
pb.RegisterHelloServer(s, &helloService{})
// Register reflection service on gRPC server.
reflection.Register(s)
if err := s.Serve(lis); err != nil {
log.Fatalf("failed to serve: %v", err)
}
}
package main
import (
pb "projects/grpcExample/proto" // 引入proto包
"log"
"os"
"golang.org/x/net/context"
"google.golang.org/grpc"
//"google.golang.org/grpc/grpclog"
)
const (
// Address gRPC服务地址
Address = "127.0.0.1:50052"
//defaultName = "world"
)
func main() {
// 连接
conn, err := grpc.Dial(Address, grpc.WithInsecure())
if err != nil {
log.Fatalf("did not connect: %v", err)
}
defer conn.Close()
// 初始化客户端
c := pb.NewHelloClient(conn)
// 调用方法
reqBody := new(pb.HelloRequest)
reqBody.Name = "gRPC"
if len(os.Args) > 1 {
reqBody.Name = os.Args[1]
}
r, err := c.SayHello(context.Background(), reqBody)
if err != nil {
log.Fatalf("could not greet: %v", err)
}
//grpclog.Info(r.Message)
//grpclog.Infoln(r.Message)
log.Printf("Greeting: %s", r.Message)
}
服务端引入编译后的proto
包,实现约定的接口,接口描述可以查看hello.pb.go
文件中的HelloServer
接口描述。实例化grpc Server
并注册HelloService
,开始提供服务。
客户端初始化连接后直接调用声明的方法,即可向服务端发起请求,使用姿势就像调用本地方法一样。