【python】之使用gRPC

gRPC Python调用

通过一个简单的工作示例使用 Python 中的 gRPC。

1 、定义rpc 接口 ,proto文件 hello.proto

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
syntax = "proto3";

option go_package="../proto";

service Greeter {
// Sends a greeting
rpc SayHello (HelloRequest) returns (HelloReply) {} // 定义rpc接口
// Sends another greeting 如果还要加就在下面添加 rpc
// rpc SayHelloAgain (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;
}

2、安装对应的库

1
pip install  grpcio、pip install grpcio-tools、pip install grpc 

3、生成py代码

1
python -m grpc_tools.protoc -I . --python_out=. --grpc_python_out=. hello.proto 

4、得到两个文件hello_pb2.py 和 hello_pb2_grpc.py

hello_pb2.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
29
30
31
32
# -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: hello.proto
# Protobuf Python Version: 4.25.1
"""Generated protocol buffer code."""
from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool
from google.protobuf import symbol_database as _symbol_database
from google.protobuf.internal import builder as _builder
# @@protoc_insertion_point(imports)

_sym_db = _symbol_database.Default()




DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0bhello.proto\"\x1c\n\x0cHelloRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\"\x1d\n\nHelloReply\x12\x0f\n\x07message\x18\x01 \x01(\t23\n\x07Greeter\x12(\n\x08SayHello\x12\r.HelloRequest\x1a\x0b.HelloReply\"\x00\x42\nZ\x08../protob\x06proto3')

_globals = globals()
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'hello_pb2', _globals)
if _descriptor._USE_C_DESCRIPTORS == False:
_globals['DESCRIPTOR']._options = None
_globals['DESCRIPTOR']._serialized_options = b'Z\010../proto'
_globals['_HELLOREQUEST']._serialized_start=15
_globals['_HELLOREQUEST']._serialized_end=43
_globals['_HELLOREPLY']._serialized_start=45
_globals['_HELLOREPLY']._serialized_end=74
_globals['_GREETER']._serialized_start=76
_globals['_GREETER']._serialized_end=127
# @@protoc_insertion_point(module_scope)

hello_pb2_grpc.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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
"""Client and server classes corresponding to protobuf-defined services."""
import grpc

# import hello_pb2 as hello__pb2
from . import hello_pb2 as hello__pb2

class GreeterStub(object):
"""Missing associated documentation comment in .proto file."""

def __init__(self, channel):
"""Constructor.

Args:
channel: A grpc.Channel.
"""
self.SayHello = channel.unary_unary(
'/Greeter/SayHello',
request_serializer=hello__pb2.HelloRequest.SerializeToString,
response_deserializer=hello__pb2.HelloReply.FromString,
)


class GreeterServicer(object):
"""Missing associated documentation comment in .proto file."""

def SayHello(self, request, context):
"""Sends a greeting
"""
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')


def add_GreeterServicer_to_server(servicer, server):
rpc_method_handlers = {
'SayHello': grpc.unary_unary_rpc_method_handler(
servicer.SayHello,
request_deserializer=hello__pb2.HelloRequest.FromString,
response_serializer=hello__pb2.HelloReply.SerializeToString,
),
}
generic_handler = grpc.method_handlers_generic_handler(
'Greeter', rpc_method_handlers)
server.add_generic_rpc_handlers((generic_handler,))


# This class is part of an EXPERIMENTAL API.
class Greeter(object):
"""Missing associated documentation comment in .proto file."""

@staticmethod
def SayHello(request,
target,
options=(),
channel_credentials=None,
call_credentials=None,
insecure=False,
compression=None,
wait_for_ready=None,
timeout=None,
metadata=None):
return grpc.experimental.unary_unary(request, target, '/Greeter/SayHello',
hello__pb2.HelloRequest.SerializeToString,
hello__pb2.HelloReply.FromString,
options, channel_credentials,
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)

5、根目录定义server.py文件,作为启动服务端

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
29
30
31
32
33
34
35
36
37
38
39
# -*- coding: utf-8 -*-
import grpc
from concurrent import futures
# import proto.stream_pb2 as stream_pb2
# import proto.stream_pb2_grpc as stream_pb2_grpc

from proto import hello_pb2, hello_pb2_grpc
import time
import base64


# 继承 hello_pb2_grpc里面的 GreeterServicer 创建服务类,必须实现GreeterServicer里面的方法
class MyGreeterServicer(hello_pb2_grpc.GreeterServicer):
# 定义服务,这个服务接收请求,返回响应
def SayHello(self, request, context):
# 在这里处理客户端的请求,并生成相应的响应数据
print(request) # request是请求,
# 请求进来后这里可以写逻辑去处理请求,比如说判断计算之类的
response_str = f"Hello, {request.name}" # 把请求处理一下,等下返回出去,
# 这里的request.name是因为你proto里定义的就是这个,发过来的 request是HelloRequest类型,
# 内容是name:"输入的内容",所以你要用request.name去拿到这个请求传入的内容

response = hello_pb2.HelloReply(message=f"response: {response_str}") # 定义响应,返回出去
return response


# 启动服务
def run_server():
server = grpc.server(futures.ThreadPoolExecutor(max_workers=10)) # 设置服务线程,
hello_pb2_grpc.add_GreeterServicer_to_server(MyGreeterServicer(), server) # 服务添加进去
server.add_insecure_port('[::]:50051') # 定义服务端口
server.start() # 开启服务
print("started server") # 打印一下确定服务开启了
server.wait_for_termination() # 等待终止,就是关闭


if __name__ == '__main__':
run_server()

6、根目录定义client.py文件,作为客户端去连接服务端

client.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
# -*- coding: utf-8 -*-
import grpc
# import stream_pb2
from proto import hello_pb2, hello_pb2_grpc


# import stream_pb2_grpc

# 启动客户端,与服务端进行连接,且发送请求
def run_client():
# wit 上下文打开会自动关闭,

# channel = grpc.insecure_channel('localhost:50051') # 如果不写with 就是这样接收
with grpc.insecure_channel('localhost:50051') as channel:
stub = hello_pb2_grpc.GreeterStub(channel) # 得到存根,存根就是代理,由这个代理去发送你的请求
print("stub:", stub) # 打印下存根,确保代理建立
request = hello_pb2.HelloRequest(name='Tom') # 定义要向服务端发送的内容
# 这里同样要注意因为你proto里面定义的 请求的字段名就是name 所以必须用name='你要传的内容'的形式去包装请求,服务端才能识别

response = stub.SayHello(request) # 得到响应 与res = requests.get(url)一个意思
print('Received response:', response.message)
# 打印响应 也是同理,因为你proto里定义返回的字段名 所以必须用response.message去取这个值


if __name__ == '__main__':
run_client()
# # Get the returned data from the trailing metadata


【python】之使用gRPC
http://example.com/2024/03/14/692python使用gRPC/
作者
Wangxiaowang
发布于
2024年3月14日
许可协议