惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

L
LINUX DO - 最新话题
G
Google Developers Blog
J
Java Code Geeks
The GitHub Blog
The GitHub Blog
F
Full Disclosure
H
Help Net Security
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Vercel News
Vercel News
酷 壳 – CoolShell
酷 壳 – CoolShell
Recent Announcements
Recent Announcements
Help Net Security
Help Net Security
The Hacker News
The Hacker News
IT之家
IT之家
Y
Y Combinator Blog
Martin Fowler
Martin Fowler
L
Lohrmann on Cybersecurity
C
CERT Recently Published Vulnerability Notes
V
Visual Studio Blog
博客园 - 聂微东
Hacker News: Ask HN
Hacker News: Ask HN
H
Hacker News: Front Page
Know Your Adversary
Know Your Adversary
Security Latest
Security Latest
Security Archives - TechRepublic
Security Archives - TechRepublic
Simon Willison's Weblog
Simon Willison's Weblog
www.infosecurity-magazine.com
www.infosecurity-magazine.com
T
Troy Hunt's Blog
Last Week in AI
Last Week in AI
Schneier on Security
Schneier on Security
N
News and Events Feed by Topic
博客园 - 【当耐特】
有赞技术团队
有赞技术团队
AWS News Blog
AWS News Blog
Blog — PlanetScale
Blog — PlanetScale
博客园_首页
Google DeepMind News
Google DeepMind News
Cloudbric
Cloudbric
N
News | PayPal Newsroom
A
About on SuperTechFans
S
Schneier on Security
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
Hugging Face - Blog
Hugging Face - Blog
M
MIT News - Artificial intelligence
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
雷峰网
雷峰网
T
The Exploit Database - CXSecurity.com
罗磊的独立博客
K
Kaspersky official blog
The Cloudflare Blog
I
Intezer

郑文峰的博客

使用dify对接飞书多维表格 使用n8n对接飞书多维表格 服务启动时出现 OOM 一次服务升级时pg表DDL执行超时失败 Go语言高效IO缓冲技术详解 Go语言延迟初始化(Lazy Initialization)最佳实践 Go语言字符串拼接性能对比与优化指南 Go语言结构体内存对齐完全指南 Go语言空结构体:零内存消耗的高效编程 Go语言堆栈分配与逃逸分析深度解析 Go语言原子操作完全指南 Go语言内存预分配完全指南 Go语言不可变数据共享:无锁并发编程实践 Go语言零拷贝技术完全指南 Go语言遍历性能深度解析:从原理到优化实践 Go语言Interface Boxing原理与性能优化指南 Go协程池深度解析:原理、实现与最佳实践 使用etcd分布式锁导致的协程泄露与死锁问题 基于pre-commit的Python代码规范落地实践 初识 MCP Server pulsar阻塞导致logstash无法接入日志 django-prometheus使用及源码分析 kube-proxy源码分析 kubernetes service如何通过iptables转发 tcp缓存引起的日志丢失 django-apschedule定时任务异常停止 理解calico容器网络通信方案原理 理解flannel的三种容器网络方案原理 理解Linux IPIP隧道 理解VXLAN网络 理解Linux TunTap设备 快速了解iptables kafka中listener和advertised.listeners的作用 django rest_framework 分页 django后端服务、logstash和flink接入VictoriaMetrics指标监控 python中import原理 docker容器单机网络 手动实现docker容器bridge网络模型 mysql之MVCC原理 mysql之日志 使用java开发logstash的filter插件 使用python实现单例模式的三种方式 redis之缓存 redis之分片集群 redis之哨兵机制 redis之主从库同步 redis之持久化 redis之五种基本数据类型 go中如何处理error pod中将代码与运行环境分离 ddt源码分析 python装饰器的使用方法 读书笔记:如何阅读一本书 使用ddt实现unittest的参数化测试 使用kubeadm安装k8s 优化gin表单的错误提示信息 gin中validator模块的源码分析 go简单使用grpc k8s之PV、PVC和StorageClass k8s之StatefulSet k8s之DaemonSet k8s之Job和CronJob k8s之ConfigMap和Secret k8s之Service k8s之Pod k8s之Deployment 容器的本质 docker容器 python迭代器与生成器 python元编程 python垃圾回收机制 python上下文管理器 django rest_framework使用jwt django rest_framework异常处理 django rest_framework 自定义文档 django压缩文件下载 django rest_framework使用pytest单元测试 django restframework choice 自定义输出数据 django Filtering 使用 django viewset 和 Router 配合使用时报的错 django model的序列化 django中使用AbStractUser django.core.exceptions.ImproperlyConfigured Application labels aren't unique, duplicates users django 中 media配置 django 外键引用自身和on_delete参数 django 警告 while time zone support is active Flask使用flask_socketio实现websocket flask结合mongo tornado 文件上传 tornado 使用jwt完成用户异步认证 tornado 用户密码 bcrypt加密 tornado 结合wtforms使用表单操作 tornado finish和write区别 tornado 使用peewee-async 完成异步orm数据库操作 pyspark streaming简介 和 消费 kafka示例 使用hue创建ozzie的pyspark action workflow count的性能优化 django rest_framework Authentication django celery 结合使用 网站
python简单使用grpc
zhengwenfeng · 2022-09-07 · via 郑文峰的博客

# 0. 相关链接

源码案例:https://github.com/tenqaz/python-examples (opens new window)

官方文档:https://grpc.io/docs/languages/python/quickstart (opens new window)

# 1. 创建protobuf文件

在目录proto目录下创建user.proto文件,创建User的rpc服务定义,该服务中包含AddUser和GetUser两个调用,并使用下面创建的对应的结构体作为请求体和响应体。 注意:需要添加package proto,否则下面编译生成的python文件引用路径则不正确。

syntax = "proto3";

// 包名
package proto;

// 定义User rpc服务
service User {
  // 定义rpc服务的方法
  rpc AddUser (UserRequest) returns (UserResponse);
  rpc GetUser (GetUserRequest) returns (GetUserResponse);
}

// 请求的结构体
message UserRequest {
  string name = 1;
  uint32 age = 2;
}

// 响应的结构体
message UserResponse {
  string msg = 1;
  int32 code = 2;
}

message GetUserRequest {
  string name = 1;
}

message GetUserResponse {
  string name = 1;
  string age = 2;
}

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

# 2. 编译proto文件

首选需要安装grpc的库和工具

python -m pip install grpcio #安装grpc
python -m pip install grpcio-tools #安装grpc tools

1
2

然后,运行命令对proto文件进行编译,会根据上面的proto文件生成对应的python文件,你会发现在proto目录下创建了user_pb2.pyuser_pb2_grpc.py两个文件

python -m grpc_tools.protoc --python_out=. --grpc_python_out=. -I. ./proto/user.proto

1

  • --python_out=.,protobuf相关代码文件生成在这里
  • --grpc_python_out=.,grpc相关代码生成在这里
  • -I. ./proto/user.proto,proto文件路径

编译后:

  • user_pb2.py,用来和 protobuf 数据进行交互,这个就是根据proto文件定义好的数据结构类型生成的python化的数据结构文件
  • user_pb2_grpc.py: 用来和 grpc 进行交互,这个就是定义了rpc方法的类,包含了类的请求参数和响应等等,可用python直接实例化调用

# 3. 简单测试protobuf数据结构的序列化与反序列化

我们创建proto_test.py文件,创建User对象,填充值,并将该对象序列化成字符串输出

from proto import user_pb2

# 创建Student对象,将该对象序列化成字符串
s = user_pb2.UserRequest()
s.name = "zhangsan"
s.age = 12
req_str = s.SerializeToString()
print(req_str)

1
2
3
4
5
6
7
8

输出:

b'\n\x08zhangsan\x10\x0c'

1

然后我们再创建User对象将将上面的输出的序列化字符串反序列化进来。

# 将上面的输出的序列化字符串反序列化成对象
s2 = user_pb2.UserRequest()
s2.ParseFromString(req_str)
print(s2.name)
print(s2.age)

1
2
3
4
5

输出:

# 4. 创建grpc服务端

下面是使用之前创建的protobuf和grpc文件来构建grpc服务端代码。

import logging
from concurrent import futures

import grpc

from proto import user_pb2, user_pb2_grpc


class UserService(user_pb2_grpc.UserServicer):

    # 实现proto文件中rpc的调用
    def AddUser(self, request: user_pb2.UserRequest, context):
        return user_pb2.UserResponse(msg='add user(name={},age={}) success'.format(request.name, request.age), code=0)

    def GetUser(self, request: user_pb2.GetUserRequest, context):
        return user_pb2.GetUserResponse(name=request.name, age="1888")


def serve():
    # 使用线程池来完成grpc的请求
    server = grpc.server(futures.ThreadPoolExecutor(max_workers=5))
    user_pb2_grpc.add_UserServicer_to_server(UserService(), server)
    server.add_insecure_port('[::]:50051')  # 绑定端口
    server.start()
    server.wait_for_termination()


if __name__ == '__main__':
    logging.basicConfig()
    serve()

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

运行该服务端,会阻塞等待客户端的请求。

# 5. 创建grpc客户端

import logging

import grpc

from proto import user_pb2, user_pb2_grpc


def run():
    # 连接rpc服务
    with grpc.insecure_channel('localhost:50051') as channel:
        stub = user_pb2_grpc.UserStub(channel)

        # 调用rpc服务的AddUser方法
        response: user_pb2.UserResponse = stub.AddUser(user_pb2.UserRequest(name="zhangsan", age=18))
        print("add user, response is 'msg={}, code={}'".format(response.msg, response.code))

        # 调用rpc服务的GetUser方法
        response: user_pb2.GetUserResponse = stub.GetUser(user_pb2.GetUserRequest(name="lisi"))
        print("get user[name={}, age={}]".format(response.name, response.age))


if __name__ == '__main__':
    logging.basicConfig()
    run()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

运行客户端,调用rpc服务,输出:

add user, response is 'msg=add user(name=zhangsan,age=18) success, code=0'
get user[name=lisi, age=1888]

1
2