python实现RPC
实现效果
通过socket实现RPC,能够从客户端调用服务端的函数并返回结果
一、socket基础
在构建自己的RPC之前,我们需要先掌握Socket的一些用法,以及什么是RPC,下面分三块讲:分别是 1、什么是socket 2、socket模块 3、套接字对象内建方法 4、什么是PRC
1.什么是socket
Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。
所以,我们无需深入理解tcp/udp协议,socket已经为我们封装好了,我们只需要遵循socket的规定去编程,写出的程序自然就是遵循tcp/udp标准的。
2.socket模块
要使用socket.socket()函数来创建套接字。其语法如下:
socket.socket(socket_family,socket_type,protocol=0)
socket_family可以是如下参数:
socket.AF_INET IPv4(默认)
socket.AF_INET6 IPv6
socket.AF_UNIX 只能够用于单一的Unix系统进程间通信
socket_type可以是如下参数:
socket.SOCK_STREAM 流式socket , for TCP (默认)
socket.SOCK_DGRAM 数据报式socket , for UDP
socket.SOCK_RAW 原始套接字,普通的套接字无法处理ICMP、IGMP等网络报文,而SOCK_RAW可以;其次,SOCK_RAW也可以处理特殊的IPv4报文;此外,利用原始套接字,可以通过IP_HDRINCL套接字选项由用户构造IP头。
socket.SOCK_RDM 是一种可靠的UDP形式,即保证交付数据报但不保证顺序。SOCK_RAM用来提供对原始协议的低级访问,在需要执行某些特殊操作时使用,如发送ICMP报文。SOCK_RAM通常仅限于高级用户或管理员运行的程序使用。
socket.SOCK_SEQPACKET 可靠的连续数据包服务
protocol参数:
0 (默认)与特定的地址家族相关的协议,如果是 0 ,则系统就会根据地址格式和套接类别,自动选择一个合适的协议
3.套接字对象内建方法
服务器端套接字函数
s.bind() 绑定地址(ip地址,端口)到套接字,参数必须是元组的格式例如:s.bind((‘127.0.0.1’,8009))
s.listen(5) 开始监听,5为最大挂起的连接数
s.accept() 被动接受客户端连接,阻塞,等待连接
客户端套接字函数
s.connect() 连接服务器端,参数必须是元组格式例如:s.connect((‘127,0.0.1’,8009))
公共用途的套接字函数
s.recv(1024) 接收TCP数据,1024为一次数据接收的大小
s.send(bytes) 发送TCP数据,python3发送数据的格式必须为bytes格式
s.sendall() 完整发送数据,内部循环调用send
s.close() 关闭套接字
4.什么是RPC
远程过程调用协议RPC(Remote Procedure Call Protocol)-----允许像调用本地服务一样调用远程服务。
二、代码实现
# 服务端 RpcServer.py
# -*- coding: utf-8 -*-
import json
import socket
funs = {}def register_function(func):"""Server端方法注册,Client端只可调用被注册的方法"""name = func.__name__funs[name] = funcclass TCPServer(object):def __init__(self):self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)self.client_socket = Nonedef bind_listen(self, port):self.sock.bind(('0.0.0.0', port))self.sock.listen(5)def accept_receive_close(self):"""获取Client端信息"""if self.client_socket is None:(self.client_socket, address) = self.sock.accept()if self.client_socket:msg = self.client_socket.recv(1024)data = self.on_msg(msg)self.client_socket.send(data) # 回传class RPCStub(object):def __init__(self):self.data = Nonedef call_method(self, data):"""解析数据,调用对应的方法变将该方法执行结果返回"""if len(data) == 0:return json.dumps("something wrong").encode('utf-8')self.data = json.loads(data.decode('utf-8'))method_name = self.data['method_name']method_args = self.data['method_args']method_kwargs = self.data['method_kwargs']res = funs[method_name](*method_args, **method_kwargs)data = resreturn json.dumps(data).encode('utf-8')class RPCServer(TCPServer, RPCStub):def __init__(self):TCPServer.__init__(self)RPCStub.__init__(self)def loop(self, port):# 循环监听 5003 端口self.bind_listen(port)print('Server listen 5003 ...')while True:try:self.accept_receive_close()except Exception:self.client_socket.close()self.client_socket = Nonecontinuedef on_msg(self, data):return self.call_method(data)@register_function
def add(a, b, c=10):sum = a + b + cprint(sum)return sum@register_function
def setData(data):print(data)return datas = RPCServer()
s.loop(5003) # 传入要监听的端口
# 客户端 RpcClient.py
# -*- coding: utf-8 -*-
import json
import socketclass TCPClient(object):def __init__(self):self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)def connect(self, host, port):"""链接Server端"""self.sock.connect((host, port))def send(self, data):"""将数据发送到Server端"""self.sock.send(data)def recv(self, length):"""接受Server端回传的数据"""return self.sock.recv(length)class RPCStub(object):def __getattr__(self, function):def _func(*args, **kwargs):d = {'method_name': function, 'method_args': args, 'method_kwargs': kwargs}self.send(json.dumps(d).encode('utf-8')) # 发送数据data = self.recv(1024) # 接收方法执行后返回的结果return data.decode('utf-8')setattr(self, function, _func)return _funcclass RPCClient(TCPClient, RPCStub):passc = RPCClient()
c.connect('127.0.0.1', 5003)
print(c.add(1, 2, 3))
print(c.setData({"sss": "ssss", "list": [1, 2, 3, 4]}))
服务端:
1、服务端对“本机的5003”端口进行监听
2、对服务端的方法进行注册“register_function”
3、对客户端传送过来的数据进行解析,查询对应的函数并将参数传入,返回给客户端
客户端:
1、客户端对服务端进行连接
2、将调用的方法名、参数传入服务端,服务端将数据进行返回
两者之间的数据采用Json文本格式
三、运行结果
服务端结果:
客户端结果:
此时我们如果再运行一次客户端
服务端结果:
客户端结果:
四、注意点
如果连接断开了(这里指客户端断开连接,如果服务端断开了,那只能重启了),需要重新创建套接字socket,重新连接
整个RPC的流程: 创建socket->建立连接->进行消息交互->关闭socket
五、后续扩充
1、在 S-C之间保持连接的时候,为了防止意外断连,可以采用心跳包的形式,每隔一段时间进行一次心跳包同步,如果断连了就重新进行socket连接
2、服务端可以将socket扩充为list,并利用address进行区分,实现多个客户端连接
六、参考文章
本文是参考下面文章整合并对代码加以改进写的
socket基础
RPC原文参考
参考二
python实现RPC相关推荐
- python rpc_对python调用RPC接口的实例详解
要调用RPC接口,python提供了一个框架grpc,这是google开源的 rpc相关文档: 需要安装的python包如下: 1.grpc安装 pip install grpcio 2.grpc的p ...
- 多语言通信基础 03 go和python的rpc通信
python有rpc开发的相关协议,同样go也有rpc的序列化协议Gob. 标准库的RPC默认采用Go语言特有的gob编码,因此从其它语言调用Go语言实现的RPC服务将比较困难.在互联网的微服务时代, ...
- python与rpc服务
什么是rpc 随着企业 IT 服务的不断发展,单台服务器逐渐无法承受用户日益增长的请求压力时,就需要多台服务器联合起来构成「服务集群」共同对外提供服务. 同时业务服务会随着产品需求的增多越来越肿,架构 ...
- Thrift中实现Java与Python的RPC互相调用
场景 Thrift介绍以及Java中使用Thrift实现RPC示例: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/1086894 ...
- python rpc框架-python使用rpc框架gRPC的方法
概述 gRPC 是谷歌开源的一个rpc(远程程序调用)框架,可以轻松实现跨语言,跨平台编程,其采用gRPC协议(基于HTTP2). rpc: remote procedure call, 翻译过来就是 ...
- python实现rpc框架_使用Python实现RPC框架
前言 本文将会使用Python实现一个最简单的RPC框架,玩具向,不具有实用意义,但可以让你清醒的理解RPC框架的几个组成部分,只是比看Python自带的xmlrpc清晰. 本文需要一点Python ...
- python 调用rpc服务_在Django项目中对Python函数进行RPC调用的优雅方式
我正在尝试创建一个django网站来访问MySQL数据库中的数据.其目的是在Dojo(javascript)中创建一个UI.另外,我希望django后端也提供webservices(RPC for p ...
- (Python)卫星RPC有理多项式模型读取与正反投影坐标计算原理与实现
(Python)卫星RPC有理多项式模型读取与正反投影坐标计算原理与实现 文章目录 (Python)卫星RPC有理多项式模型读取与正反投影坐标计算原理与实现 摘要 RPC几何定位模型介绍 RPC模型库 ...
- python测试rpc接口_python使用grpc调用rpc接口
#Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! importgrpcimportcoupon_pb2 as c ...
- java调用python的RPC接口
依赖 <!--XMRPC相关依赖--><dependency><groupId>org.apache.xmlrpc</groupId><artif ...
最新文章
- 【CentOS】利用Kubeadm部署Kubernetes (K8s)
- 江苏省专转本计算机教程,江苏省专转本计算机基础复习(含真题)教程.doc
- C#中多线程同步的Monitor理解
- 黑火药跟黄火药的区别在哪里?
- android布局之线性布局
- MySQL高级 全表扫描更快
- github --- 多个项目的管理方式
- T-SQL 字符串前加 N 是什么意思
- linux龙芯自动挂载u盘,Windows Subsystem for Linux (WSL)挂载移动硬盘U盘
- HDOJ 1757 A Simple Math Problem(矩阵快速幂)
- java中int边界值_数组中重复的数字2019.12.06
- 第一个C#程序—C#基础回顾
- JNI 调用 DLL
- snipaste截图软件安装各种问题解决办法
- AutoCAD二次开发学习记录一:批量统计dwg文件数据
- 信息学奥赛一本通(c++):1125:矩阵乘法
- 【VSCode教程】 C++第一个DLL、远离手动GCC、快速自动生成、来 say_helloヽ(^o^)丿
- 疫情之后,各地智慧灯杆政策与项目发布情况汇总
- 《青浦区加快发展跨境电子商务实施细则(审议稿)》
- 监听队列中linux方法ss -a,Linux命令:ss命令
热门文章
- EOF和scanf函数
- pythorch显卡利用率过低的问题
- java计算机毕业设计智慧物业管理系统源码+数据库+lw文档+系统+部署
- 【NOJ1142】【算法实验二】踩气球
- The least populated class in y has only 1 member, which is too few. The minimum number of groups for
- 利用Idea生成的类图分析框架源码
- 【ZYNQ】QSPI Flash 固化程序全攻略
- 优秀课件笔记english-writing专业英语写作5
- 从头开始用树莓派做一个NAS【最新超详细教程】
- 西门子 S7-1200 与 BL200PN 通信示例