Pythonのxmlrpcモジュールを参照してPickle-RPCを実装しました。RPC経由でプロパティにアクセスする方法
クライアント側からは、RPCサーバーに登録されているインスタンスのメソッドを呼び出すことができます。
s = ServerProxy(('127.0.0.1', 49152), DatagramRequestSender)
s.foo('bar')
プロパティにもアクセスしたいです。
s = ServerProxy(('127.0.0.1', 49152), DatagramRequestSender)
s.foobar
どのように実装すればよいですか?
client.py
import pickle
import socket
from io import BytesIO
class StreamRequestSender:
max_packet_size = 8192
address_family = socket.AF_INET
socket_type = socket.SOCK_STREAM
def send_request(self, address, request):
with socket.socket(self.address_family, self.socket_type) as client_socket:
with client_socket.makefile('wb') as wfile:
pickle.dump(request, wfile)
with client_socket.makefile('rb') as rfile:
response = pickle.load(rfile)
return response
class DatagramRequestSender(StreamRequestSender):
socket_type = socket.SOCK_DGRAM
def send_request(self, address, request):
with socket.socket(self.address_family, self.socket_type) as client_socket:
with BytesIO() as wfile:
pickle.dump(request, wfile)
client_socket.sendto(wfile.getvalue(), address)
data = client_socket.recv(self.max_packet_size)
with BytesIO(data) as rfile:
response = pickle.load(rfile)
return response
class ServerProxy:
def __init__(self, address, RequestSenderClass):
self.__address = address
self.__request_sender = RequestSenderClass()
def __send(self, method, args):
request = (method, args)
response = self.__request_sender.send_request(self.__address, request)
return response
def __getattr__(self, name):
return _Method(self.__send, name)
class _Method:
def __init__(self, send, name):
self.__send = send
self.__name = name
def __getattr__(self, name):
return _Method(self.__send, "{}.{}".format(self.__name, name))
def __call__(self, *args):
return self.__send(self.__name, args)
if __name__ == '__main__':
s = ServerProxy(('127.0.0.1', 49152), DatagramRequestSender)
print(s.pow(2, 160))
server.py
import pickle
import sys
from socketserver import StreamRequestHandler, DatagramRequestHandler, ThreadingTCPServer, ThreadingUDPServer
class RPCRequestHandler:
def handle(self):
method, args = pickle.load(self.rfile)
response = self.server.dispatch(method, args)
pickle.dump(response, self.wfile)
class StreamRPCRequestHandler(RPCRequestHandler, StreamRequestHandler):
pass
class DatagramRPCRequestHandler(RPCRequestHandler, DatagramRequestHandler):
pass
class RPCDispatcher:
def __init__(self, instance=None):
self.__instance = instance
def register_instance(self, instance):
self.__instance = instance
def dispatch(self, method, args):
_method = None
if self.__instance is not None:
try:
_method = self._resolve_dotted_attribute(self.__instance, method)
except AttributeError:
pass
if _method is not None:
return _method(*args)
else:
raise Exception('method "{}" is not supported'.format(method))
@staticmethod
def _resolve_dotted_attribute(obj, dotted_attribute):
attributes = dotted_attribute.split('.')
for attribute in attributes:
if attribute.startswith('_'):
raise AttributeError('attempt to access private attribute "{}"'.format(attribute))
else:
obj = getattr(obj, attribute)
return obj
class RPCServer(ThreadingUDPServer, RPCDispatcher):
def __init__(self, server_address, RPCRequestHandlerClass, instance=None):
ThreadingUDPServer.__init__(self, server_address, RPCRequestHandlerClass)
RPCDispatcher.__init__(self, instance)
if __name__ == '__main__':
class ExampleService:
def pow(self, base, exp):
return base ** exp
s = RPCServer(('127.0.0.1', 49152), DatagramRPCRequestHandler, ExampleService())
print('Serving Pickle-RPC on localhost port 49152')
print('It is advisable to run this example server within a secure, closed network.')
try:
s.serve_forever()
except KeyboardInterrupt:
print("\nKeyboard interrupt received, exiting.")
s.server_close()
sys.exit(0)
Pyro4の 'Proxy'クラスは、正しく理解すれば、動的に管理された' _pyroAttrs'を使ってリモート属性を受け取ります。コミュニケーションなしにメソッド/プロパティを動的に解決することはできません。 P.S. Pyro4はとても良いライブラリです。私は何かを聞きたい。その1つ、Pyro 4はTCPとUDPの違いをどのように吸収しますか?ありがとうございました。 – sira
私はあなたの質問を理解していません。 Pyro4はTCP/IPソケットを排他的に使用しているため、Pyroのやり方ではUDP(パケットの順序を保証していない信頼性の低いプロトコル)で信頼性の高いRPCを実行する方法はありませんが、これを議論する場所:) –
ああ、私は参照してください。ありがとうございました。 – sira