实现效果

通过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相关推荐

  1. python rpc_对python调用RPC接口的实例详解

    要调用RPC接口,python提供了一个框架grpc,这是google开源的 rpc相关文档: 需要安装的python包如下: 1.grpc安装 pip install grpcio 2.grpc的p ...

  2. 多语言通信基础 03 go和python的rpc通信

    python有rpc开发的相关协议,同样go也有rpc的序列化协议Gob. 标准库的RPC默认采用Go语言特有的gob编码,因此从其它语言调用Go语言实现的RPC服务将比较困难.在互联网的微服务时代, ...

  3. python与rpc服务

    什么是rpc 随着企业 IT 服务的不断发展,单台服务器逐渐无法承受用户日益增长的请求压力时,就需要多台服务器联合起来构成「服务集群」共同对外提供服务. 同时业务服务会随着产品需求的增多越来越肿,架构 ...

  4. Thrift中实现Java与Python的RPC互相调用

    场景 Thrift介绍以及Java中使用Thrift实现RPC示例: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/1086894 ...

  5. python rpc框架-python使用rpc框架gRPC的方法

    概述 gRPC 是谷歌开源的一个rpc(远程程序调用)框架,可以轻松实现跨语言,跨平台编程,其采用gRPC协议(基于HTTP2). rpc: remote procedure call, 翻译过来就是 ...

  6. python实现rpc框架_使用Python实现RPC框架

    前言 本文将会使用Python实现一个最简单的RPC框架,玩具向,不具有实用意义,但可以让你清醒的理解RPC框架的几个组成部分,只是比看Python自带的xmlrpc清晰. 本文需要一点Python ...

  7. python 调用rpc服务_在Django项目中对Python函数进行RPC调用的优雅方式

    我正在尝试创建一个django网站来访问MySQL数据库中的数据.其目的是在Dojo(javascript)中创建一个UI.另外,我希望django后端也提供webservices(RPC for p ...

  8. (Python)卫星RPC有理多项式模型读取与正反投影坐标计算原理与实现

    (Python)卫星RPC有理多项式模型读取与正反投影坐标计算原理与实现 文章目录 (Python)卫星RPC有理多项式模型读取与正反投影坐标计算原理与实现 摘要 RPC几何定位模型介绍 RPC模型库 ...

  9. python测试rpc接口_python使用grpc调用rpc接口

    #Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! importgrpcimportcoupon_pb2 as c ...

  10. java调用python的RPC接口

    依赖 <!--XMRPC相关依赖--><dependency><groupId>org.apache.xmlrpc</groupId><artif ...

最新文章

  1. 【CentOS】利用Kubeadm部署Kubernetes (K8s)
  2. 江苏省专转本计算机教程,江苏省专转本计算机基础复习(含真题)教程.doc
  3. C#中多线程同步的Monitor理解
  4. 黑火药跟黄火药的区别在哪里?
  5. android布局之线性布局
  6. MySQL高级 全表扫描更快
  7. github --- 多个项目的管理方式
  8. T-SQL 字符串前加 N 是什么意思
  9. linux龙芯自动挂载u盘,Windows Subsystem for Linux (WSL)挂载移动硬盘U盘
  10. HDOJ 1757 A Simple Math Problem(矩阵快速幂)
  11. java中int边界值_数组中重复的数字2019.12.06
  12. 第一个C#程序—C#基础回顾
  13. JNI 调用 DLL
  14. snipaste截图软件安装各种问题解决办法
  15. AutoCAD二次开发学习记录一:批量统计dwg文件数据
  16. 信息学奥赛一本通(c++):1125:矩阵乘法
  17. 【VSCode教程】 C++第一个DLL、远离手动GCC、快速自动生成、来 say_helloヽ(^o^)丿
  18. 疫情之后,各地智慧灯杆政策与项目发布情况汇总
  19. 《青浦区加快发展跨境电子商务实施细则(审议稿)》
  20. 监听队列中linux方法ss -a,Linux命令:ss命令

热门文章

  1. EOF和scanf函数
  2. pythorch显卡利用率过低的问题
  3. java计算机毕业设计智慧物业管理系统源码+数据库+lw文档+系统+部署
  4. 【NOJ1142】【算法实验二】踩气球
  5. The least populated class in y has only 1 member, which is too few. The minimum number of groups for
  6. 利用Idea生成的类图分析框架源码
  7. 【ZYNQ】QSPI Flash 固化程序全攻略
  8. 优秀课件笔记english-writing专业英语写作5
  9. 从头开始用树莓派做一个NAS【最新超详细教程】
  10. 西门子 S7-1200 与 BL200PN 通信示例