国际惯例,先从helloworld例子开始,了解一下使用grpc的流程。
第一步 编写proto文件 定义我们的服务:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 syntax = "proto3"; package helloworld; // The greeting service definition. service Greeter { // Sends a greeting rpc SayHello (HelloRequest) returns (HelloReply) {} } // The request message containing the user's name. message HelloRequest { string name = 1; } // The response message containing the greetings message HelloReply { string message = 1; }
定义服务 使用”service”定义服务,一个服务可以提供多个rpc方法。:
service Greeter { // (Method definitions not shown) }
定义RPC方法 使用”rpc”在服务中定义rpc方法,并指定方法的请求和响应消息类型。
gRPC允许定义4种rpc方法,后面会详细介绍。
客户端可以使用存根调用这个rpc方法,然后等待回应,就像本地调用一样。
rpc SayHello (HelloRequest) returns (HelloReply) {}
定义消息
使用”message”定义所有请求的 protocol buffer 消息类型定义以及在服务方法中使用的响应类型
// The request message containing the user’s name. message HelloRequest { string name = 1; }
// The response message containing the greetings message HelloReply { string message = 1; }
这里使用的都是简单的string类型,后面的”=1”是protocol buffer序列化和反序列化时使用的”key”,后面会专门讲解protocol buffer编码机制。
第二步,生成客户端和服务端代码 python比较顺手,我们以python说明。
上一节讲过,我们现在要使用protoc工具和对应的python插件生成代码,安装好相关工具后,执行以下命令生成代码:
1 > protoc -I ../../protos/ --python_out=. --grpc_out=. --plugin=protoc-gen-grpc=`which grpc_python_plugin` ../../protos/helloworld.proto
会生成2个py文件:helloworld_pb2.py,helloworld_pb2_grpc.py
这2文件的作用分别是: helloworld_pb2.py:这个文件包含消息定义及protocol buffer编码相关代码
helloworld_pb2_grpc.py:这个文件包含客户端调用存根和服务端的抽象类。
不同语言大都会生成这2类文件。
然后我们使用这2个生成的文件分别编写客户端和服务端代码。
客户端实现:
greeter_client.py:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 from __future__ import print_functionimport grpcimport helloworld_pb2 import helloworld_pb2_grpcdef run (): with grpc.insecure_channel('localhost:50051' ) as channel: stub = helloworld_pb2_grpc.GreeterStub(channel) response = stub.SayHello(helloworld_pb2.HelloRequest(name='you' )) print ("Greeter client received: " + response.message) if __name__ == '__main__' : run()
greeter_server.py:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 from concurrent import futures import timeimport grpcimport helloworld_pb2 import helloworld_pb2_grpc_ONE_DAY_IN_SECONDS = 60 * 60 * 24 class Greeter (helloworld_pb2_grpc.GreeterServicer ):def SayHello (self, request, context ): return helloworld_pb2.HelloReply(message='Hello, %s!' % request.name) def serve (): server = grpc.server(futures.ThreadPoolExecutor(max_workers=10 )) helloworld_pb2_grpc.add_GreeterServicer_to_server(Greeter(), server) server.add_insecure_port('[::]:50051' ) server.start() try : while True : time.sleep(_ONE_DAY_IN_SECONDS) except KeyboardInterrupt: server.stop(0 ) if __name__ == '__main__' : serve()
第三步 运行 分别运行server,client代码,即可。