1

我创建了一个简单的RPC服务器来执行我们团队常见的某些任务,但这些任务是从不同的网络调用的。服务器看起来像这样(为简洁起见,我不包括错误处理):

from twisted.internet.protocol import Protocol, Factory
from twisted.internet import reactor
import json

class MyProtocol(Protocol):
    def dataReceived(self, data):
        req = json.loads(data) # create a dictionary from JSON string
        method = getattr(self, req['method']) # get the method
        method(req['params']) # call the method

    def add(self, params):
        result = {} # initialize a dictionary to convert later to JSON
        result['result'] = sum(params) 
        result['error'] = None 
        result['id'] = 1
        self.transport.write(json.dumps(result)) # return a JSON string
        self.transport.loseConnection() # close connection

factory = Factory()
factory.protocol = MyProtocol
reactor.listenTCP(8080, factory)
reactor.run()

这很简单:服务器接收到客户端的 JSON RPC 请求,查找方法,并调用传递参数的方法。方法本身就是返回 JSON RPC 响应的方法。对于不太熟悉的人,JSON RPC大致如下所示:

request:
{"method":"my_method", "params":[1,2,3], "id":"my_id"}
response:
{"result":"my_result", "error":null, "id":"my_id"}

我拥有的 RPC 服务器非常适合我当前的目的(您可以想象,我的任务非常简单)。但随着任务复杂性的增加,我将需要继续添加方法。

我不想打开主文件并添加另一个def method3(...),两周后添加def method4(...)等等;代码会增长太快,维护会越来越难。

所以,我的问题是:如何创建允许我将方法注册到 Server的架构。一个好处是每个方法都有一个单独的文件夹保存一个文件,以便可以轻松地共享和维护它们。这种“架构”还允许我将某些方法的维护推迟给其他人,无论他们对 Twisted 的理解如何。

我不在乎每次注册新方法时是否需要重新启动服务器,但如果我没有的话,一个明显的优点是:)。

谢谢。

4

1 回答 1

1

有点大的订单;)但这里有一些初始步骤(在示例中省略了非常严重的模拟,扭曲的细节):

# your twisted imports...
import json

class MyProtocol(object): # Would be Protocol instead of object in real code

    def dataReceived(self, data):
        req = json.loads(data) # create a dictionary from JSON string
        modname, funcname = req['method'].split('.')
        m = __import__(modname)
        method = getattr(m, funcname) # get the method
        method(self, req['params']) # call the method

假设您尝试一下,就好像我们执行了这个:

mp = MyProtocol()
mp.dataReceived('{"method":"somemod.add", "params":[1,2,3]}')

您将somemod.py在与示例相同的目录中拥有一个具有以下内容的模块(反映.add()上面的示例方法):

import json

def add(proto, params):
    result = {} # initialize a dictionary to convert later to JSON
    result['result'] = sum(params)
    result['error'] = None
    result['id'] = 1
    proto.transport.write(json.dumps(result)) # return a JSON string
    proto.transport.loseConnection() # close connection

这允许您为每种方法提供一个模块。上面的method(..调用将始终将您的MyProtocol实例传递给服务可调用对象。(如果你真的想要实例方法,这里有关于如何使用 python 添加方法的说明:http: //irrepupavel.com/documents/python/instancemethod/

您将需要添加大量错误处理。例如,您需要在split()第 2 行的调用中进行大量错误检查dataReceived()

有了这个,您可以为需要支持的每种方法拥有单独的文件,其中包含一个功能。绝不是一个完整的例子,但它可能会让你继续前进,因为你正在寻找的东西非常复杂。

对于更正式的注册,我建议使用您支持的方法名称,如下所示dictMyProtocol

# in MyProtocol's __init__() method:
self.methods = {}

还有一个注册方法..

def register(self, name, callable):
    self.methods[name] = callable

..修改dataReceived()..

def dataReceived(self, data):
    # ...
    modname, funcname = self.methods.get(req['method'], False)
    # ..continue along the lines of the dataReceived() method above

一篇过长的帖子的快速总结:__import__函数(http://docs.python.org/library/functions.html)肯定会成为您解决方案的关键部分。

于 2010-07-07T20:42:30.833 回答