网站首页 返回列表 像“草根”一样,紧贴着地面,低调的存在,冬去春来,枯荣无恙。

gRPC初体验

2020-06-10 11:21:29 admin 1154

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

  • 和REST一样遵循HTTP协议(明确的说是HTTP/2),但是gRPC提供了全双工流
  • 和传统的REST不同的是gRPC使用了静态路径,从而提高性能
  • 用一些格式化的错误码代替了HTTP的状态码更好的标示错误

至于是否要选择用gRPC。对于已经有一套方案的团队,可以参考下。如果是从头来做,可以考虑下gRPC提供的从客户端到服务器的整套解决方案,这样不用客户端去实现http的请求会话,JSON等的解析,服务器端也有现成的框架用。从15年3月到现在gRPC也发展了一年了,慢慢趋于成熟。下面我们就以gRPC的Golang版本看下其在golang上面的表现。至于服务端的RPC,感觉golang标准库的RPC框架基本够用了,没必要再去用另一套方案。

1. 安装protobuf

虽然gRPC也支持protobuf2.x,但是建议还是使用protobuf3.x,尽管还没有正式版本,不过golang版本基本没有什么问题,另外3.x官方支持了Objective-C,这也是我们使用gRPC的初衷:提供一个移动端到服务器的解决方案。去到Protocol
Buffers
下载最新版本(Version3.0.0
beta2),然后解压到本地。本地需要已经安装好autoconf automake libtool.rpm系列(fedora/centos/redheat)可以用yum安装。Mac上可以用brew进行安装

__

  1. brew install autoconf automake libtool

然后执行

__

  1. . /configure --prefix=your_pb_install_path

接着

__

  1. make
  2. make install
  3. set your_pb_install_path to your $PATH

检查是否安装完成

__

  1. protoc --version
  2. libprotoc 3.0.0

然后安装golang protobuf直接使用golang的get即可

__

  1. go get -u github.com/golang/protobuf/proto // golang protobuf 库
  2. go get -u github.com/golang/protobuf/protoc-gen-go //protoc --go_out 工具

2. 安装gRPC-go

gRPC-go可以通过golang 的get命令直接安装,非常方便。

__

  1. go get google.golang.org/grpc

这里大家可能比较奇怪,为什么gRPC-go在github的地址是”https://github.com/grpc/grpc-
go
“,但是为什么要用“google.golang.org/grpc”进行安装呢?应该grpc原本是google内部的项目,归属golang,就放在了google.golang.org下面了,后来对外开放,又将其迁移到github上面了,又因为golang比较坑爹的import路径规则,所以就都没有改路径名了。

但是这样就有个问题了。要如何去管理版本呢?这个目前我还没有什么比较好的方法,希望知道的朋友一起分享下。目前想到一个方法是手动下载某个版本,然后写个脚本统一修改代码中的import里面的路径.

3. 示例程序

3.1 protobuf

该示例源自gRPC-go的examples的helloworld。先看PB的描述:

__

  1. syntax = "proto3";
  2. option objc_class_prefix = "HLW";
  3. package helloworld;
  4. // The greeting service definition.
  5. service Greeter {
  6. // Sends a greeting
  7. rpc SayHello (HelloRequest) returns (HelloReply) {}
  8. }
  9. // The request message containing the user's name.
  10. message HelloRequest {
  11. string name = 1;
  12. }
  13. // The response message containing the greetings
  14. message HelloReply {
  15. string message = 1;
  16. }

这里定义了一个服务Greeter,其中有个API
SayHello。其接受参数为HelloRequest类型,返回HelloReply类型。这里HelloRequestHelloReply就是普通的PB定义

服务定义为:

__

  1. // The greeting service definition.
  2. service Greeter {
  3. // Sends a greeting
  4. rpc SayHello (HelloRequest) returns (HelloReply) {}
  5. }

service定义了一个server。其中的接口可以是四种类型

  • rpc GetFeature(Point) returns (Feature) {}
    类似普通的函数调用,客户端发送请求Point到服务器,服务器返回相应Feature.

  • rpc ListFeatures(Rectangle) returns (stream Feature) {}
    客户端发起一次请求,服务器端返回一个流式数据,比如一个数组中的逐个元素

  • rpc RecordRoute(stream Point) returns (RouteSummary) {}
    客户端发起的请求是一个流式的数据,比如数组中的逐个元素,服务器返回一个相应

  • rpc RouteChat(stream RouteNote) returns (stream RouteNote) {}
    客户端发起的请求是一个流式数据,比如数组中的逐个元素,二服务器返回的也是一个类似的数据结构

后面三种可以参考官方的route_guide示例。

使用protoc命令生成相关文件:

__

  1. protoc --go_out=plugins=grpc:. helloworld.proto
  2. ls
  3. helloworld.pb.go helloworld.proto

生成对应的pb.go文件。这里用了plugins选项,提供对grpc的支持,否则不会生成Service的接口。

3.2 服务器端程序

然后编辑服务器端程序:

__

  1. package main
  2. import (
  3. "log"
  4. "net"
  5. pb "your_path_to_gen_pb_dir/helloworld"
  6. "golang.org/x/net/context"
  7. "google.golang.org/grpc"
  8. )
  9. const (
  10. port = ":50051"
  11. )
  12. // server is used to implement helloworld.GreeterServer.
  13. type server struct{}
  14. // SayHello implements helloworld.GreeterServer
  15. func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
  16. return &pb.HelloReply{Message: "Hello " + in.Name}, nil
  17. }
  18. func main() {
  19. lis, err := net.Listen("tcp", port)
  20. if err != nil {
  21. log.Fatalf("failed to listen: %v", err)
  22. }
  23. s := grpc.NewServer()
  24. pb.RegisterGreeterServer(s, &server{})
  25. s.Serve(lis)
  26. }

这里首先定义一个server结构,然后实现SayHello的接口,其定义在“your_path_to_gen_pb_dir/helloworld”

__

  1. SayHello (context.Context, *HelloRequest) (*HelloReply, error)

然后调用grpc.NewServer() 创建一个server s。接着注册这个server s到结构server上面
pb.RegisterGreeterServer(s, &server{})
最后将创建的net.Listener传给s.Serve()。就可以开始监听并服务了,类似HTTP的ListenAndServe。

3.3 客户端程序

客户端程序:

__

  1. package main
  2. import (
  3. "log"
  4. "os"
  5. pb "your_path_to_gen_pb_dir/helloworld"
  6. "golang.org/x/net/context"
  7. "google.golang.org/grpc"
  8. )
  9. const (
  10. address = "localhost:50051"
  11. defaultName = "world"
  12. )
  13. func main() {
  14. // Set up a connection to the server.
  15. conn, err := grpc.Dial(address, grpc.WithInsecure())
  16. if err != nil {
  17. log.Fatalf("did not connect: %v", err)
  18. }
  19. defer conn.Close()
  20. c := pb.NewGreeterClient(conn)
  21. // Contact the server and print out its response.
  22. name := defaultName
  23. if len(os.Args) > 1 {
  24. name = os.Args[1]
  25. }
  26. r, err := c.SayHello(context.Background(), &pb.HelloRequest{Name: name})
  27. if err != nil {
  28. log.Fatalf("could not greet: %v", err)
  29. }
  30. log.Printf("Greeting: %s", r.Message)
  31. }

这里通过pb.NewGreeterClient()传入一个conn创建一个client,然后直接调用client上面对应的服务器的接口

__

  1. SayHello (context.Context, *HelloRequest) (*HelloReply, error)

接口,返回*HelloReply 对象。

先运行服务器,在运行客户端,可以看到。

__

  1. ./greeter_server&
  2. ./greeter_client
  3. 2016/03/10 21:42:19 Greeting: Hello world
转载文章,原文链接: gRPC初体验

关键字词grpc初体验

分享到:

如需留言,请 登录,没有账号?请 注册

0 条评论 0 人参与

顶部 底部