在gRPC中,客户端应用程序可以直接在其他计算机上的服务器应用程序上调用方法,就好像它是本地对象一样,从而使您更轻松地创建分布式应用程序和服务。与许多RPC系统一样,gRPC围绕定义服务的思想,指定可通过其参数和返回类型远程调用的方法。在服务器端,服务器实现此接口并运行gRPC服务器以处理客户端调用。在客户端,客户端具有一个存根(在某些语言中仅称为客户端),提供与服务器相同的方法。
默认情况下,gRPC使用协议缓冲区,这是谷歌成熟的开源机制,用于序列化结构化数据(尽管它也可以用于其他数据格式,如JSON)。使用协议缓冲区时,第一步是为要在proto文件中序列化的数据定义结构:这是一个扩展名为.proto的普通文本文件。协议缓冲区数据结构为消息,其中每个消息都是包含一系列名为字段的名称-值对的信息的小逻辑记录。这里有一个简单的例子:
syntax = "proto3";
service Math{
rpc add(Params) returns(Response){}
rpc reduce(Params) returns(Response){}
}
message Params{
int32 num1 = 1;
int32 num2 = 2;
}
message Response{
int32 result = 1;
}
grpc使用protobuf进行数据传输,protobuf是一种数据交换格式,由三部分组成:
rpc get_feature(Params) returns(Response){}
rpc get_feature(Params) returns(stream Response){}
rpc get_feature(stream Params) returns(Response){}
rpc get_feature(stream Params) returns(stream Response){}
安装grpc与grpc工具包
pip3 install grpcio
pip3 install grpcio-tools
有这么一个文件math.proto
,内容如下:
syntax = "proto3";
service Math{
rpc add(Params) returns(Response){}
rpc reduce(Params) returns(Response){}
}
message Params{
int32 num1 = 1;
int32 num2 = 2;
}
message Response{
int32 result = 1;
}
编译.proto文件
/**
-I 指定工作目录
--python_out 指定python文件目录
--grpc_python_out 指定grpc python文件目录
**/
python3 -m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. ./math.proto
执行上面的命令进行编译之后,会在当前目录生成math_pb2.py
和math_pb2_grpc.py
文件。服务端代码如下:
import grpc
from concurrent import futures
import math_pb2
import math_pb2_grpc
class MathServer(math_pb2_grpc.MathServicer):
def add(self, request, context):
return math_pb2.Response(result=request.num1 + request.num2)
def reduce(self, request, content):
return math_pb2.Response(result=request.num1 - request.num2)
if __name__ == '__main__':
server = grpc.server(futures.ThreadPoolExecutor(max_workers=5))
math_pb2_grpc.add_MathServicer_to_server(MathServer(), server)
server.add_insecure_port("[::]:50001")
server.start()
print('server is starting...')
server.wait_for_termination()
客户端代码如下:
import grpc
import math_pb2
import math_pb2_grpc
channel = grpc.insecure_channel("localhost:50001")
stub = math_pb2_grpc.MathStub(channel)
def add(num1, num2):
response = stub.add(math_pb2.Params(num1=num1, num2=num2))
print(f'response: {response.result}')
def reduce(num1, num2):
response = stub.reduce(math_pb2.Params(num1=num1, num2=num2))
print(f'response: {response.result}')
if __name__ == '__main__':
add(1, 2)
我们可以使用import
指令来导入其他的proto文件。假设有这么两个文件types.proto
和math.proto
。types.proto
文件内容如下:
syntax = "proto3";
package types;
message Params{
int32 num1 = 1;
int32 num2 = 2;
}
message Response{
int32 result = 1;
}
现在我们需要在math.proto
文件中调用这个types.proto
文件的内容。math.proto
文件内容如下:
syntax = "proto3";
// protos/types.proto表示在protos文件夹下面的types.proto文件
import "protos/types.proto";
service Math{
// types为types.proto文件中的package名称
rpc add(types.Params) returns(types.Response){}
rpc reduce(types.Params) returns(types.Response){}
}
更多grpc的使用:https://www.grpc.io/docs/