grpc在python中的使用

本文介绍gRPC的安装配置及与protobuf的结合使用方法,包括数据格式定义、Python文件生成、服务器与客户端代码示例等内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

GRPC

grpc使用
protobuf
官网

安装:

pip install grpcio #gRPC 的安装
pip install protobuf #ProtoBuf 相关的 python 依赖库
pip install grpcio-tools #python grpc 的 protobuf 编译工具

protobuf

// camera.proto,定义数据格式
syntax = "proto3"; // 定义proto3版本,是推荐版本,也可以用proto2
service Camera {   //定义服务
    rpc CreateCamera(CameraInfo) returns (CameraInfo) {}
    rpc RequestImage(CameraInfo) returns (ImageResponse) {}
}
//定义相关数据类型,
message NDArray {
    string data_type = 1;
    repeated int32 shape = 2;
    bytes data = 3;
}
message CameraInfo { //定义数据类型,用于传参,可有嵌套使用,类似于类,只是赋值为编号
    string camera_name = 1;
    string camera_ip = 2;
    float image_exposure = 3;
    float point_cloud_exposure = 4;
    int32 running_flag = 5;
    repeated float roi = 6;//repeated用于数组定义
    int32 gain = 7;
    bool auto_gain = 8;
}
protobuf常见数据类型包括:
float、double、int32、int64、uint32、uint64、sint32、sint64、bool、string、bytes等
用protobuf生成python文件
python -m grpc_tools.protoc --python_out=. --grpc_python_out=. -I. helloworld.proto
# 生成两个.py文件
# camera_pb2.py: 用来和 protobuf 数据进行交互, 名字跟proto文件名有相关性
# camera_pb2_grpc.py: 用来和 grpc 进行交互, 名字跟proto文件名有相关性
python -m grpc_tools.protoc: python 下的 protoc 编译器通过 python 模块(module) 实现
--python_out=. : 编译生成处理 protobuf 相关的代码的路径, 可自定义
--grpc_python_out=. : 编译生成处理 grpc 相关的代码的路径, 可自定义
-I. helloworld.proto : proto 文件的路径

服务器端代码

# 对使用而言,若将proto文件中定义的Servicer的实现放到下面的api_rpc文件中去调用,这个文件基本是固定的,也可在服务器端实现Servicer
import time
import grpc
from concurrent import futures
from backend.camera.grpc_camera.camera_api_rpc import CameraService
from backend.camera.grpc_camera import camera_service_pb2_grpc
def serve():
    print("server start!")
    MAX_MESSAGE_LENGTH = 1024*1024*1024 
    # 定义服务器并设置最大连接数,corcurrent.futures是一个并发库,类似于线程池的概念,options定义数据传输大小,默认最大传输4M
    server = grpc.server(futures.ThreadPoolExecutor(max_workers=4), options=[
               ('grpc.max_send_message_length', MAX_MESSAGE_LENGTH),
               ('grpc.max_receive_message_length', MAX_MESSAGE_LENGTH),
               ]) 
    camera_service_pb2_grpc.add_CameraServicer_to_server(CameraService(), server)# 添加服务,第一个参数为定义并在文api_rpc文件中实现的server类
    server.add_insecure_port('[::]:9901')
    server.start()
    try:
        while True:
            time.sleep(3600)
    except KeyboardInterrupt:
        server.stop(0)

客户端代码

MAX_MESSAGE_LENGTH = 1024*1024*1024
channel = grpc.insecure_channel('127.0.0.1:9901', \
     options = [('grpc.max_send_message_length',MAX_MESSAGE_LENGTH), ('grpc.max_receive_message_length',MAX_MESSAGE_LENGTH)]) # 连接服务器 
 # with grpc.insecure_channel('127.0.0.1:9901') as self.channel:
stub = camera_service_pb2_grpc.CameraStub(self.channel) # 调用服务,即调用proto函数生成的py文件中的类
camera_info = camera_service_pb2.CameraInfo(  # 构造消息体,传送参数
    camera_name = args['CAMERA']["camera_name"],# 给参数赋值
    camera_ip = args['CAMERA']["camera_ip"],
    image_exposure = args['CAMERA']["exposure_time"],
    point_cloud_exposure = args['CAMERA']["exposure_time"],
    running_flag = args['CAMERA']["running_flag"],
    roi = [args['CAMERA']["roi"][0], args['CAMERA']["roi"][1], args['CAMERA']["roi"][2], args['CAMERA']["roi"][3]],
    gain = args['CAMERA']["gain"],
    auto_gain = args['CAMERA']["auto_gain"]
)
response = stub.CreateCamera(camera_info)  # 调用服务器端的函数

在api_grpc中实现proto文件中定义的Servicer

# 可以在此实现proto文件中定义的server,也可以对复杂数据类型进行转换
from backend.camera.grpc_camera import camera_service_pb2, camera_service_pb2_grpc
# 此处的定义要与proto文件中的定义名字,返回值,参数等保持一致
class CameraService(camera_service_pb2_grpc.CameraServicer):
    def CreateCamera(self, request, context):
    	pass
    	return request
    def RequestImage(self, request, context):
    	pass
    def RequestImageAndPointCloud(self, request, context):
    	pass

设置消息大小

在打开服务器或客户端的时候设置
client:

MAX_MESSAGE_LENGTH = 256*1024*1024  # 可根据具体需求设置,此处设为256M
channel = grpc.insecure_channel(‘localhost:50051,
								options = [(‘grpc.max_send_message_length’,MAX_MESSAGE_LENGTH),
								(‘grpc.max_receive_message_length’,MAX_MESSAGE_LENGTH)
								])

server:

MAX_MESSAGE_LENGTH = 256*1024*1024  # 可根据具体需求设置,此处设为256M
server = grpc.server(futures.ThreadPoolExecutor(max_workers=10), options=[
               ('grpc.max_send_message_length', MAX_MESSAGE_LENGTH),
               ('grpc.max_receive_message_length', MAX_MESSAGE_LENGTH),
               ] )

流式数据处理

主要使用for _ in () yield, 见开头参考文章中的内容

4 种通信方式

reference

1. 客户端单次请求,服务端回应一次:
// Obtains the feature at a given position.
rpc GetFeature(Point) returns (Feature) {}

2. 客户端一次请求,服务端流式应答(其实相当于返回给客户端多条数据)
// Obtains the Features available within the given Rectangle.  Results are
// streamed rather than returned at once (e.g. in a response message with a
// repeated field), as the rectangle may cover a large area and contain a
// huge number of features.
rpc ListFeatures(Rectangle) returns (stream Feature) {}

3. 客户端流式请求,服务端回应一次
// Accepts a stream of Points on a route being traversed, returning a
// RouteSummary when traversal is completed.
rpc RecordRoute(stream Point) returns (RouteSummary) {}

4. 客户端流式请求,服务端流式应答
// Accepts a stream of RouteNotes sent while a route is being traversed,
// while receiving other RouteNotes (e.g. from other users).
rpc RouteChat(stream RouteNote) returns (stream RouteNote) {}

异常处理

reference

踩过的坑

  1. 在将grpc用到软件中时,对multiprocess的manager使用不熟导致数据更新有问题
    manager中dict不可拆分到不同进程中使用,跳出拆分后的进程回到主进程时,是不会将dict的值更新的。
  2. grpc采用客户端和服务器,就相当于一个新的进程,跟原主进程是不冲突的。
  3. 若在循环中调用grpc,会一直运行grpc的内容而影响主进程,可将调用变成一个线程,然后线程进入grpc久是单独进程,不会影响到主进程的更新和运行 。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值