本文需要一点Python socket基础。
回顾RPC

客户端(Client):服务调用方。
客户端存根(Client Stub):存放服务端地址信息,将客户端的请求参数数据信息打包成网络消息,再通过网络传输发送给服务端。
服务端存根(Server Stub):接收客户端发送过来的请求消息并进行解包,然后再调用本地服务进行处理。
服务端(Server):服务的真正提供者。
Network Service:底层传输,可以是 TCP 或 HTTP。
实现jsonrpc
在实现前,简单理一下整体思路。
1、Network Service 直接使用Python Socket相关的API实现 2.传输数据使用JSON,在Socket层会被压成二进制,我们无需关心。
模仿xmlrpc,Client与Server都采用Minix多继承机制来实现,每个类负责自身的事情,最终暴露出现的只有一个类中有限的方法。
先从Client端开始实现。
# client.py
import rpcclient
c
= rpcclient
.RPCClient
()
c
.connect
(127.0.0.1, 5000)
res
= c
.add
(1, 2, c
=3)
print(f
res: [{res}])
实例化rpcclient.RPCClient类,然后调用connect方法链接Server端,随后直接调用Server端的add方法,该方法的效果就是将传入的数据进行累加并将累加的结果返回,最后将add方法返回的结果打印出了。
RPCClient类继承于TCPClient类与RPCStub类。
# rpclient.py
class RPCClient(TCPClient
, RPCStub
):
pass
其中TCPClient负责通过Socket实现TCP链接并将数据请求过去,而RPCStub类主要将Client端调用Server端方法的相关信息打包,然后调用TCPClient类中的方法发送则可,两个类同样实现在rpclient.py文件中,代码如下。
class 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
setattr(self
, function
, _func
)
return _func
TCPClient类就是常规的Socket API的操作,无需多言,主要看看RPCStub类。
当我们在Client端调用res = c.add(1, 2, c=3)时,会执行RPCStub中的__getattr__方法,该方法会将Client端调用的方法、参数等信息通过TCPServer类的send方法发送,发送数据进行了JSON格式化,方便Server端解码,随后便调用recv方法等待Server端相应的数据返回。
因为RPCClient类本身没有add方法,为了让用户做到Client端直接调用Server端方法的形式,先利用__getattr__构建了_func方法,并将其通过setattr方法设置到RPCClient类中,此时该类就有Server端方法对应的映射了。
调用add方法,就调用了对应的_func方法,将数据发送至Server端。
Client端就这样搞定了,接着来实现Server端,不用紧张,非常简单。
Server端的使用方式如下。
# server.py
import rpcserver
def add(a
, b
, c
=10):
sum = a
+ b
+ c
return sum
s
= rpcserver
.RPCServer
()
s
.register_function
(add
) # 注册方法
s
.loop
(5000) # 传入要监听的端口
实例化rpcserver.RPCServer类,然后通过register_function方法将想被Client端调用的方法传入,随后调用loop方法,将要监听的端口传入,RPCServer类的实现如下。
# rpcserver.py
class RPCServer(TCPServer
, JSONRPC
, RPCStub
):
def __init__(self
):
TCPServer
.__init__
(self
)
JSONRPC
.__init__
(self
)
RPCStub
.__init__
(self
)
def loop(self
, port
):
# 循环监听 5000 端口
self
.bind_listen
(port
)
print(Server listen 5000 …)
while True:
self
.accept_receive_close
()
def on_msg(self
, data
):
return self
.call_method
(data
)
RPCServer继承自TCPServer、JSONRPC、RPCStub,这些类同样实现在rpcserver.py文件中并且给出了详细的注释,所以就详细解释了。
class TCPServer(object):
def __init__(self
):
self
.sock
= socket
.socket
(socket
.AF_INET
, socket
.SOCK_STREAM
)
def bind_listen(self
, port
):
self
.sock
.bind
((0.0.0.0, port
))
self
.sock
.listen
(5)
def accept_receive_close(self
):
获取Client端信息
(client_socket
, address
) = self
.sock
.accept
()
msg
= client_socket
.recv
(1024)
data
= self
.on_msg
(msg
)
client_socket
.sendall
(data
) # 回传
client_socket
.close
()
class JSONRPC(object):
def __init__(self
):
self
.data
= None
def from_data(self
, data
):
解析数据
self
.data
= json
.loads
(data
.decode
(utf-8))
def call_method(self
, data
):
解析数据,调用对应的方法变将该方法执行结果返回
self
.from_data
(data
)
method_name
= self
.data
[method_name]
method_args
= self
.data
[method_args]
method_kwargs
= self
.data
[method_kwargs]
res
= self
.funs
[method_name
](*method_args
, **method_kwargs
)
data
= {“res”: res
}
return json
.dumps
(data
).encode
(utf-8)
class RPCStub(object):
def __init__(self
):
self
.funs
= {}
def register_function(self
, function
, name
=None):
Server端方法注册,Client端只可调用被注册的方法
if name
is None:
name
= function
.__name__
self
.funs
[name
] = function
至此,Client端和Server端都写好了。
测试:

以上就是python实现一个简单RPC框架的示例的详细内容。