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()

これは非常に簡単です。サーバーはクライアントからJSONRPCリクエストを受信し、メソッドを探し、パラメーターを渡してメソッドを呼び出します。メソッド自体は、JSONRPC応答を返すメソッドです。あまり馴染みのない人にとっては、JSONRPCはおおよそ次のようになります。

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

私が持っているRPCサーバーは、現在の目的を非常にうまく果たしています(ご想像のとおり、私のタスクは非常に単純です)。ただし、タスクの複雑さが増すにつれて、メソッドを追加し続ける必要があります。

def method3(...)メインファイルを開いてさらに別のファイルを追加し、2週間後に追加するなどしたくありませんdef method4(...)。コードの成長が速すぎて、メンテナンスがますます難しくなります。

だから、私の質問は、サーバーにメソッドを登録できるアーキテクチャをどのように作成できるかということです。ボーナスは、メソッドごとに1つのファイルを保持する別のフォルダーを用意して、それらを簡単に共有および保守できるようにすることです。この「アーキテクチャ」により、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

これにより、メソッドごとに1つのモジュールを提供できます。上記のmethod(..呼び出しは、常にMyProtocolインスタンスをサービング呼び出し可能オブジェクトに渡します。(インスタンスメソッドが本当に必要な場合は、Pythonを使用してメソッドを追加する方法について説明します:http://irrepupavel.com/documents/python/instancemethod/

多くのエラー処理を追加する必要があります。たとえば、のsplit()2行目の呼び出しで多くのエラーチェックが必要ですdataReceived()

これにより、サポートする必要のあるメソッドごとに1つの関数を含む個別のファイルを作成できます。完全な例というわけではありませんが、探しているものは非常に複雑なので、うまくいくかもしれません。

より正式な登録については、次の行に沿って、サポートするメソッドの名前を含むdictinをお勧めします。MyProtocol

# 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 に答える