当前位置: 首页 > news >正文

gRPC 使用(python 版本)

.proto 文件

.proto 文件gRPC 和 Protocol Buffers 的接口定义文件,它描述了:

  1. 要传递什么数据(也就是消息体 message)。
  2. 要暴露什么接口(也就是服务 service 和它们的 方法)。

也就是一份规范文件,让客户端和服务端能按照相同的约定相互通信。

my_service.proto

syntax = "proto3";  // 指定使用 proto3 语法版本package demo;       // 包名,方便生成代码时分模块service MyService {// 定义 RPC 服务rpc Predict(PredictRequest) returns (PredictResponse) {}
}message PredictRequest {string prompt = 1;
}message PredictResponse {string result = 1;
}
  1. 用 protoc 自动生成客户端/服务端代码
    这里使用 python 来进行操作
python -m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. my_service.proto
  • I. 指定 proto 搜索路径为当前目录
  • -python_out=. 生成 my_service_pb2.py(定义消息类型)
  • -grpc_python_out=. 生成 my_service_pb2_grpc.py(定义服务类接口)

因为 gRPC 要跨语言,所以必须有语言无关的描述文件

  • .proto 就是统一规范

  • Protocol Buffers 定义数据传输结构(比 JSON 轻量、高速、强类型)

  • gRPC 框架用它生成客户端/服务端、自动序列化、自动网络传输

  • protoc 会以输入文件 my_service.proto 的文件名为基准自动生成对应的 Python 文件。

  • 它没有单独的参数去自定义生成文件名,所以默认就是:

    ✅ my_service_pb2.py:

    • 包含你 .proto 中定义的 message 和 enum 类型对应的 Python 类。

    ✅ my_service_pb2_grpc.py:

    • 包含你 .proto 中定义的 service 和 RPC 方法对应的客户端和服务端桩代码。
<proto文件名>_pb2.py
<proto文件名>_pb2_grpc.py
文件包含内容用途
my_service_pb2.py消息类型类(message、enum)序列化/反序列化数据
my_service_pb2_grpc.py服务类和客户端/服务端接口实现服务逻辑/调用远程服务
  • pb2.py → 负责数据模型
  • pb2_grpc.py → 负责服务调用逻辑(RPC 接口)

服务端实现

from concurrent import futures
import grpc
import my_service_pb2
import my_service_pb2_grpc# 实现 RPC 服务
class MyService(my_service_pb2_grpc.MyServiceServicer):
# 是生成的服务端基类,这里我们继承它并实现 Predict 方法逻辑。def Predict(self, request, context):print(f"Received prompt: {request.prompt}")return my_service_pb2.PredictResponse(result=f"Hello, {request.prompt}!")# 启动 gRPC 服务器
def serve():server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))my_service_pb2_grpc.add_MyServiceServicer_to_server(MyService(), server)server.add_insecure_port("[::]:50051")server.start()print("gRPC Server running at 0.0.0.0:50051...")server.wait_for_termination()if __name__ == "__main__":serve()#  python -m grpc_tools.protoc -I. --pytheon_out=. --grpc_python_out=. my_service.proto

✅ grpc.server(…) 创建 gRPC 服务器实例,并给它分配一个线程池(能同时处理多个请求)。

✅ add_MyServiceServicer_to_server(MyService(), server) 注册我们自己实现的服务逻辑。

✅ server.add_insecure_port(“[::]:50051”) 打开监听端口。

✅ server.start() 启动服务,wait_for_termination() 让服务持续监听,不会自动结束。

_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'my_service_pb2', _globals)

  • 动态注册生成消息类

也就是:

  • PredictRequest、PredictResponse 这些类在导入时动态创建,IDE 静态分析器(比如 PyCharm)无法提前知道它们存在,因此你用 IDE 查看时找不到定义。
  • 但是程序运行时,这些类会存在,并能正常使用。
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x10my_service.proto\x12\x04\x64\x65mo\" \n\x0ePredictRequest\x12\x0e\n\x06prompt\x18\x01 \x01(\t\"!\n\x0fPredictResponse\x12\x0e\n\x06result\x18\x01 \x01(\t2E\n\tMyService\x12\x38\n\x07Predict\x12\x14.demo.PredictRequest\x1a\x15.demo.PredictResponse\"\x00\x62\x06proto3')
  • AddSerializedFile(…) 把你 .proto 定义编译成的二进制描述数据注册进 DescriptorPool。
  • 也就是把整个 my_service.proto 的结构信息(服务、消息类型、字段等)塞入一个描述池中。

客户端实现

import grpc
import my_service_pb2
import my_service_pb2_grpcdef run_client():channel = grpc.insecure_channel("localhost:50051")stub = my_service_pb2_grpc.MyServiceStub(channel)response = stub.Predict(my_service_pb2.PredictRequest(prompt="World111"))print(f"Server response: {response.result}")if __name__ == "__main__":run_client()

客户端主要做三件事:

  1. 建立 gRPC 连接(channel)。
  2. 使用自动生成的 stub 来调用服务端方法。
  3. 接收服务端返回的响应并打印。
代码部分解释
grpc.insecure_channel()使用未加密通道(适合本地测试,不推荐生产环境直接用这个,要用 TLS 版 secure_channel())
MyServiceStub(channel)这是 gRPC 自动生成的客户端类,内部已经帮你实现好了 RPC 序列化、反序列化逻辑
PredictRequest()使用自动生成的类构造 RPC 请求对象,这个类对应你的 proto 中定义的消息类型
stub.Predict(…)相当于远程调用服务端的 Predict(),gRPC 会自动序列化请求、网络传输、反序列化响应
response.result服务端返回的 PredictResponse 消息对象,取它的 result 字段就是你服务返回的内容

🚀 客户端 vs 服务端对应关系

服务端:

class MyService(my_service_pb2_grpc.MyServiceServicer):def Predict(self, request, context):return my_service_pb2.PredictResponse(result=f"Hello, {request.prompt}!")

客户端:

response = stub.Predict(my_service_pb2.PredictRequest(prompt="World111")
)

客户端调用 Predict() 时:

  • 底层帮你序列化 prompt 参数并传给服务端
  • 服务端执行对应逻辑并返回 result 给客户端
  • 客户端拿到结果打印出来 🎉

也可以使用 go 来客户端,注意先

protoc --go_out=. --go-grpc_out=. my_service.proto

go

package mainimport ("context""log""time""google.golang.org/grpc"pb "path/to/generated/my_service" // 引入生成的包
)func main() {// 1️⃣ 建立 gRPC 连接conn, err := grpc.Dial("localhost:50051", grpc.WithInsecure()) if err != nil {log.Fatalf("连接失败: %v", err)}defer conn.Close()// 2️⃣ 创建客户端存根client := pb.NewMyServiceClient(conn)// 3️⃣ 调用服务ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)defer cancel()resp, err := client.Predict(ctx, &pb.PredictRequest{Prompt: "Hello Go!"})if err != nil {log.Fatalf("调用错误: %v", err)}log.Printf("服务返回: %s\n", resp.Result)
}

总结

无论是 gRPC、腾讯的 tRPC,甚至国内很多 RPC 框架(例如阿里 HSF、蚂蚁 SOFA RPC),它们背后的实现思路都是一样的👇:

🔄共同点:

  1. 先定义接口协议(IDL)

    用 proto、.thrift、.proto3 或者类似 IDL 文件描述你的服务、方法、消息。

  2. 代码生成器生成对应语言的客户端/服务端存根

    protoc、trpcproto 或者对应语言插件 → 自动生成:

    • 服务接口类(Stub / Service 接口)
    • 消息类(序列化 / 反序列化逻辑)
  3. 服务端实现 Service 类逻辑

    你只需继承生成的服务接口,然后实现方法逻辑即可。

  4. 客户端用生成的存根调用方法

    就像调用本地函数一样,不需要手动拼接网络数据、序列化二进制流。

.proto 文件↓
[生成工具] 自动生成代码↓
服务端: 实现 Service 类
客户端: 使用 Client Stub 调用↓
底层负责网络传输、序列化、负载均衡、错误处理...

减少重复代码 — 不用你手写网络序列化部分

强类型检查 — 调用方/服务方都能知道数据结构

方便跨语言调用 — 一份协议,不同语言都能生成对应客户端、服务端

减少网络细节关注 — 把网络部分封装起来

http://www.lryc.cn/news/575373.html

相关文章:

  • 2025学年湖北省职业院校技能大赛 “信息安全管理与评估”赛项 样题卷(五)
  • Axure版TDesign 组件库-免费版
  • MQTT 和 HTTP 有什么本质区别?
  • 如何将 Memfault 固件 SDK 集成到使用 Nordic 的 nRF Connect SDK(NCS)的项目中
  • 数据结构进阶 - 第四,五章 串、数组和广义表
  • Docker 入门教程(一):从概念到第一个容器
  • 水质指数预测模型R²偏低的原因分析与优化策略
  • 2-深度学习挖短线股-1-股票范围选择
  • uniapp微信小程序:editor组件placeholder字体样式修改
  • vue3 + elementPlus 封装hook,检测form表单数据修改变更;示例用 script setup 语法使用
  • SpringBoot项目快速开发框架JeecgBoot——Web处理!
  • 一次开发,多端适配!全面掌握Dioxus跨平台开发框架!
  • 远程玩3A大作要多少帧?ToDesk、向日葵、UU远程性能对决
  • 面试破局:告别流水账,用“故事思维”重塑自我介绍
  • rocketmq中broker和namesrv的区别和联系?
  • 川翔云电脑全新上线:三维行业高效云端算力新选择
  • 智能化监管:微算法科技(NASDAQ:MLGO)比特币社区分类器助力加密货币市场规范发展
  • CRON表达式编辑器与定时任务实现技术文档
  • 阿里云ACP-检索分析服务
  • fnm node包管理器
  • 《解锁FFmpeg - python:开启多媒体处理新时代》
  • GNSS位移监测站在大坝安全中的用处
  • Lynx vs React Native vs Flutter 全面对比:三大跨端框架实测分析
  • PAT A 1052 Linked List Sorting
  • 解决uniapp vue3版本封装组件后:deep()样式穿透不生效的问题
  • ZYNQ GP总线深度实战:智能灯光控制器的PS-PL交互艺术
  • Python 惰性求值实战:用生成器重构 Sentence 类
  • 从HTML4到HTML5+CSS3,如何快速掌握?(有老版HTML基础或经验)
  • Web基础关键_001_HTML(一)
  • QTextEdit、QTextBrowser右键菜单汉化显示