[Python] RPC实现
单线程同步
- 使用socket传输数据
- 使用json序列化消息体
- struct将消息编码为二进制字节串,进行网络传输
消息协议


- 1 // 输入
- 2 {
- 3 in: "ping",
- 4 params: "ireader 0"
- 5 }
- 6
- 7 // 输出
- 8 {
- 9 out: "pong",
- 10 result: "ireader 0"
- 11 }
客户端 client.py


- 1 # coding: utf-8
- 2 # client.py
- 3
- 4 import json
- 5 import time
- 6 import struct
- 7 import socket
- 8
- 9
- 10 def rpc(sock, in_, params):
- 11 response = json.dumps({"in": in_, "params": params}) # 请求消息体
- 12 length_prefix = struct.pack("I", len(response)) # 请求长度前缀
- 13 sock.sendall(length_prefix)
- 14 sock.sendall(response)
- 15 length_prefix = sock.recv(4) # 响应长度前缀
- 16 length, = struct.unpack("I", length_prefix)
- 17 body = sock.recv(length) # 响应消息体
- 18 response = json.loads(body)
- 19 return response["out"], response["result"] # 返回响应类型和结果
- 20
- 21 if __name__ == '__main__':
- 22 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- 23 s.connect(("localhost", 8080))
- 24 for i in range(10): # 连续发送10个rpc请求
- 25 out, result = rpc(s, "ping", "ireader %d" % i)
- 26 print out, result
- 27 time.sleep(1) # 休眠1s,便于观察
- 28 s.close() # 关闭连接
服务端 blocking_single.py


- 1 # coding: utf8
- 2 # blocking_single.py
- 3
- 4 import json
- 5 import struct
- 6 import socket
- 7
- 8
- 9 def handle_conn(conn, addr, handlers):
- 10 print addr, "comes"
- 11 while True: # 循环读写
- 12 length_prefix = conn.recv(4) # 请求长度前缀
- 13 if not length_prefix: # 连接关闭了
- 14 print addr, "bye"
- 15 conn.close()
- 16 break # 退出循环,处理下一个连接
- 17 length, = struct.unpack("I", length_prefix)
- 18 body = conn.recv(length) # 请求消息体
- 19 request = json.loads(body)
- 20 in_ = request['in']
- 21 params = request['params']
- 22 print in_, params
- 23 handler = handlers[in_] # 查找请求处理器
- 24 handler(conn, params) # 处理请求
- 25
- 26
- 27 def loop(sock, handlers):
- 28 while True:
- 29 conn, addr = sock.accept() # 接收连接
- 30 handle_conn(conn, addr, handlers) # 处理连接
- 31
- 32
- 33 def ping(conn, params):
- 34 send_result(conn, "pong", params)
- 35
- 36
- 37 def send_result(conn, out, result):
- 38 response = json.dumps({"out": out, "result": result}) # 响应消息体
- 39 length_prefix = struct.pack("I", len(response)) # 响应长度前缀
- 40 conn.sendall(length_prefix)
- 41 conn.sendall(response)
- 42
- 43
- 44 if __name__ == '__main__':
- 45 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 创建一个TCP套接字
- 46 sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # 打开reuse addr选项
- 47 sock.bind(("localhost", 8080)) # 绑定端口
- 48 sock.listen(1) # 监听客户端连接
- 49 handlers = { # 注册请求处理器
- 50 "ping": ping
- 51 }
- 52 loop(sock, handlers) # 进入服务循环
多线程同步
- 使用线程库thread创建原生线程
- 服务器可并行处理多个客户端
服务端 multithread.py

多进程同步
- Python的GIL导致单个进程只能占满一个CPU核心,多线程无法利用多核优势
- os.fork()会生成子进程
- 子进程退出后,父进程需使用waitpid系统调用收割子进程,防止其称为僵尸资源
- 在子进程中关闭服务器套接字后,在父进程中也要关闭服务器套接字
- 因为进程fork后,父子进程都有自己的套接字引用指向内核的同一份套接字对象,套接字引用计数为2,对套接字进程close,即将套接字对象的引用计数减1
服务端 multiprocess.py

PreForking同步
- 进程比线程耗费资源,通过PreForking进程池模型对服务器开辟的进程数量进行限制,避免服务器负载过重
- 如果并行的连接数量超过了prefork进程数量,后来的客户端请求将会阻塞
单进程异步
- 通过事件轮询API,查询相关套接字是否有响应的读写事件,有则携带事件列表返回,没有则阻塞
- 拿到读写事件后,可对事件相关的套接字进行读写操作
- 设置读写缓冲区
- Nginx/Nodejs/Redis都是基于异步模型
- 异步模型编码成本高,易出错,通常在公司业务代码中采用同步模型,仅在讲究高并发高性能的场合才使用异步模型
PreForking异步
- Tornado/Nginx采用了多进程PreForking异步模型,具有良好的高并发处理能力
参考
Python多线程和多进程
https://www.cnblogs.com/yssjun/p/11302500.html
[Python] RPC实现的更多相关文章
- Python RPC 之 gRPC
gRPC 简介: gRPC 是一款高性能.开源的 RPC 框架,产自 Google,基于 ProtoBuf 序列化协议进行开发,支持多种语言(Golang.Python.Java等),本篇只介绍 Py ...
- Python RPC 不会?不妨看看这篇文章
1. 前言 大家好,我是安果! RPC,全程为 Remote Procedure Call,是一种进程间的通信方式,它采用「 服务端 / 客户机 」模式,是一种请求响应模型 其中,服务端负责提供服务程 ...
- python rpc 的实现
所谓RPC,是远程过程调用(Remote Procedure Call)的简写,网上解释很多,简单来说,就是在当前进程调用其他进程的函数时,体验就像是调用本地写的函数一般.本文实现的是在本地调用远端的 ...
- python使用grpc调用rpc接口
proto文件: syntax = "proto3"; package coupon; // //message UnsetUseC2URequest { // int64 bid ...
- python thrift使用实例
前言 Apache Thrift 是 Facebook 实现的一种高效的.支持多种编程语言的远程服务调用的框架.本文将从 Python开发人员角度简单介绍 Apache Thrift 的架构.开发和使 ...
- RPC简介及框架选择
简单介绍RPC协议及常见框架,对比传统restful api和RPC方式的优缺点.常见RPC框架,gRPC及序列化方式Protobuf等 HTTP协议 http协议是基于tcp协议的,tcp协议是流式 ...
- 服务治理与RPC · 跬步
以前写过Django中使用zerorpc的方法,但是由于我们的Django是运行在gevent下,而zeromq需要启动一个后台进程处理消息,与gevent使用的greenlet携程是冲突的. 在Ja ...
- Odoo14 rpc
odoo14中rpc调用分为两种. 一种是外部调用rpc来访问odoo数据,这个时候你需要登录授权. 另一种是我们自己编写的widget小部件或者自定义视图时候通过js通过rpc去获取数据. 这里说的 ...
- [源码解析] PyTorch 分布式 Autograd (3) ---- 上下文相关
[源码解析] PyTorch 分布式 Autograd (3) ---- 上下文相关 0x00 摘要 我们已经知道 dist.autograd 如何发送和接受消息,本文再来看看如何其他支撑部分,就是如 ...
随机推荐
- DNS 缓存中毒--Kaminsky 攻击复现
0x00 搭建实验环境 使用3台Ubuntu 16.04虚拟机,可到下面的参考链接下载 攻击的服务是BIND9,由于条件限制,这里使用本地的一台虚拟机当作远程DNS解析器,关闭了DNSSEC服务,其中 ...
- Scrum完整项目实例
一.背景 在谈 JIRA 之前,就不得不说说敏捷开发了.正式由于项目是基于敏捷开发进行的,因此才引入了 JIRA 这款适合于敏捷开发的项目管理工具.当然,这里不会大篇章的介绍敏捷开发,之前的文章有详细 ...
- ClickHouse性能优化?试试物化视图
一.前言 ClickHouse是一个用于联机分析(OLAP)的列式数据库管理系统(DBMS):目前我们使用CH作为实时数仓用于统计分析,在做性能优化的时候使用了 物化视图 这一特性作为优化手段,本文主 ...
- .net 开源模板引擎jntemplate 教程:基础篇之在ASP.NET MVC中使用Jntemplate
在ASP.NET MVC 中使用Jntemplate 上一篇我们详细介绍了jntemplate的标签语法,本篇文章将继续介绍如何在ASP.NET MVC 中使用Jntemplate. 一.使用Jnte ...
- Dynamics CRM实体系列之视图
这一节开始讲视图.视图在Dynamics CRM中代表着实体的数据展示列表,通过这个列表可以对数据进行一个初步预览,也可以进行一些数据的定向筛选和搜索进行精确的浏览一部分数据.同时视图也是查看详细实体 ...
- 做个开源博客学习Vite2 + Vue3 (三)博客设计和代码设计
项目搭建好了之后是不是可以编码了呢? 等等不要着急,我们是不是应该先设计一下?比如博客的功能等? 博客设计 先做个简单的个人博客,因为是个人版,所以可以省略注册.登录这些功能,表结构也可以简单一点. ...
- Day09_41_集合_Set
Set集合 Set集合 - Set集合的特点是无序不可重复.Set集合类似于一个罐子,程序可以依次把多个对象"丢进"Set集合,而Set集合通常不能记住元素的添加顺序. - Set ...
- 实现服务端和客户端的实时双向数据传输-WebSocket简单了解
WebSocket 前段时间项目中遇到了消息推送的问题,当时采用客户端轮询,每隔 5s 请求一次数据.由于轮询的效率低,非常浪费资源.后面准备把轮询调整为使用 WebSocket 来建立连接,实现推送 ...
- java 读取ini文件
1.情景:需要将硬代码写到文件中,这样以后改动只需改动灵活 1)txt文件,需要将这code字符串读到代码中,保存成数组 2)导包:pom.xml添加依赖: <dependency> &l ...
- 漫画 | 公司测试因提Bug不规范,锒铛入狱~
互联网人罪状系列 1.上班第一天,前端把后端告上县衙,还列了 5 宗罪 2. 程序员状告产品经理八大罪状 (上) 3.程序员状告产品经理八大罪状(下) 开发人员与测试人员的关系,就如同程序员与产品经理 ...