图书查询RPC协议练习
前置:理解客户端/服务端、请求响应、流式返回与期限;本机示例使用 Python 3.10+,依赖版本见下文。教学范围为proto3;Python3.10+;grpcio/grpcio-tools1.76.0;protobuf6.33.0。核对日期2026-10-17。示例未执行,本轮没有安装依赖、生成协议代码、启动服务或浏览器预览。完整源码和输入文件见下方「同源完整文件」;推演结论只适用于写明的模型。
完整图书查询协议
完整图书查询协议包含GetBook与StreamBooks,固定示例书目仅两本,不接数据库。proto声明请求和返回类型,服务端按ID查找,流式按书号排序;客户端显式设置两秒期限。仅用于本机读者将来自跑,默认绑定127.0.0.1且无TLS,不能直接公网部署。
图书RPC预期结果
图书RPC预期结果为GetBook的b1返回书名Algorithms,流式返回b1再b2。空ID返回INVALID_ARGUMENT,不存在的b9返回NOT_FOUND;服务没启动则客户端可报UNAVAILABLE。预期结果均未执行,生成文件也未在本轮产生。
RPC失败契约练习
RPC失败契约练习分别判断空ID等参数错误、未知ID与客户端期限过短的状态,并说明取消后哪些工作可以停。若将方法改成预留图书,重试必须加入请求键与持久去重,不能保留当前纯查询假设直接承诺恰好一次。
同源完整文件
以下README含前置、输入、读者自跑步骤、预期结果、失败、恢复与清理;只做静态核对,没有执行。
library.proto
syntax = "proto3";
package library.v1;
service Library {
rpc GetBook(GetBookRequest) returns (Book);
rpc StreamBooks(ListBooksRequest) returns (stream Book);
}
message GetBookRequest { string id = 1; }
message ListBooksRequest {}
message Book {
string id = 1;
string title = 2;
optional string subtitle = 3;
reserved 4;
reserved "legacy_author";
}requirements.txt
grpcio==1.76.0
grpcio-tools==1.76.0
protobuf==6.33.0server.py
from concurrent import futures
import grpc
import library_pb2 as pb
import library_pb2_grpc as rpc
BOOKS = {'b1': 'Algorithms', 'b2': 'Operating Systems'}
class Library(rpc.LibraryServicer):
def GetBook(self, request, context):
if not request.id:
context.abort(grpc.StatusCode.INVALID_ARGUMENT, 'id required')
if request.id not in BOOKS:
context.abort(grpc.StatusCode.NOT_FOUND, 'book not found')
return pb.Book(id=request.id, title=BOOKS[request.id])
def StreamBooks(self, request, context):
for key in sorted(BOOKS):
if not context.is_active():
return
yield pb.Book(id=key, title=BOOKS[key])
def main():
server = grpc.server(futures.ThreadPoolExecutor(max_workers=2))
rpc.add_LibraryServicer_to_server(Library(), server)
if server.add_insecure_port('127.0.0.1:50051') == 0:
raise RuntimeError('cannot bind teaching port')
server.start()
try:
server.wait_for_termination()
except KeyboardInterrupt:
server.stop(2).wait()
if __name__ == '__main__':
main()client.py
import sys
import grpc
import library_pb2 as pb
import library_pb2_grpc as rpc
def main():
identifier = sys.argv[1] if len(sys.argv) > 1 else 'b1'
with grpc.insecure_channel('127.0.0.1:50051') as channel:
stub = rpc.LibraryStub(channel)
try:
book = stub.GetBook(pb.GetBookRequest(id=identifier), timeout=2)
print(book.id, book.title)
for item in stub.StreamBooks(pb.ListBooksRequest(), timeout=2):
print(item.id, item.title)
except grpc.RpcError as error:
print(error.code().name, error.details(), file=sys.stderr)
return 2
return 0
if __name__ == '__main__':
sys.exit(main())README.md
# gRPC调用契约:完整示例
示例未执行。核对日期2026-10-17。教学版本族:proto3;Python3.10+;grpcio/grpcio-tools1.76.0;protobuf6.33.0。
## 文件与依赖
文件:library.proto, requirements.txt, server.py, client.py。requirements.txt为同源依赖声明;所有代码和配置都随本文展示。本例的 Python 库版本由 requirements.txt 固定;协议生成与启动命令见下文,本轮没有安装依赖或生成代码。
## 输入与前置
前置:理解客户端与服务端、请求响应、服务端流和截止时间。使用 Python 3.10+,依赖 requirements.txt 中固定版本的 grpcio、grpcio-tools 和 protobuf;先生成本例协议代码,再在同机两个终端运行服务端与客户端。书号参数及状态预期见下节。
读者将来自跑(本轮没有执行):先在独立虚拟环境核对并安装requirements.txt;在本目录生成协议文件:
```text
python -m pip install -r requirements.txt
python -m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. library.proto
python server.py
```
另一个终端在同一目录用同一虚拟环境执行`python client.py b1`,失败样例为`python client.py b9`与`python client.py ""`。PowerShell/Bash均从本例目录调用,环境激活语法按平台选择。服务仅监听本机;按Ctrl+C优雅停服,确认终端退出后删除专用虚拟环境与生成的library_pb2.py、library_pb2_grpc.py即可,勿删除原schema。生成产物未提交也未在本轮生成,路径和导入关系由完整proto定义可重建。
## 预期结果、失败与恢复
GetBook(b1)预期id=b1,title=Algorithms;空ID为INVALID_ARGUMENT;b9为NOT_FOUND;StreamBooks按b1、b2依次给出。客户端超时可能与服务端成功并存,不能推定服务端回滚。
失败要保留输入和错误,先与正文的不变量及边界核对。没有真实服务或性能验证,不以这些模型输出证明生产可用性。若将本例查询扩展为有副作用的预留操作,需重新设计持久去重与重试契约。
## 独立练习
为空ID、未知ID和已过期限各写一个处理决定;再讨论将查询变成预留后如何重试。
参考答案:空ID是INVALID_ARGUMENT,不重试先修输入;未知ID是NOT_FOUND,查资源或修ID;期限失败需增加合理预算或减少工作,不能无限重试。预留有副作用,需要同一请求键和持久结果记录,超时后查询原请求状态。先作答,再核对
为空ID、未知ID和已过期限各写一个处理决定;再讨论将查询变成预留后如何重试。
逐步参考解答
空ID是INVALID_ARGUMENT,不重试先修输入;未知ID是NOT_FOUND,查资源或修ID;期限失败需增加合理预算或减少工作,不能无限重试。预留有副作用,需要同一请求键和持久结果记录,超时后查询原请求状态。
按请求值走到明确状态码
GetBook 是查询,空字符串在查表前拒绝;合法形式但不存在的b9返回NOT_FOUND。StreamBooks则返回排序后的两本书,客户端读完还应检查流最终状态,不能把收到第一本当成整次RPC成功。图只描述原示例固定数据,不含数据库、网络实测或权限系统。
查看图表代码
来源与适用边界
- 英文官方、作者或规范原文:本专题机制依据;按上述固定版本族阅读。
- 中文官方或作者资料:用于术语和讲解交叉核对,冲突以原始规范为准。
- 截止时间、取消、生成工具1.76.0:源码仅静态复核,兼容与网络流程未执行。
继续阅读
- 调用与生命周期