2

我有一个使用 python 扭曲库开发的以下代码:

class Cache(protocol.Protocol):
    def __init__(self, factory):
        self.factory = factory

    def dataReceived(self, data):
        request = json.loads(data)
        self.factory.handle[request['command']](**request)
        self.transport.write(data)

class CacheFactory(protocol.Factory):
    def buildProtocol(self, addr):
        return Cache(self)
    def handle_get(self, **kwargs):
        print 'get\n', kwargs
    def handle_set(self, **kwargs):
        print 'set\n', kwargs
    def handle_delete(self, **kwargs):
        print 'delete\n', kwargs
    handle = {
        'get': handle_get,
        'set': handle_set,
        'delete': handle_delete,
    }

reactor.listenTCP(int(sys.argv[1]), CacheFactory())
reactor.run()

我使用 telnet 运行客户端连接:

Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
{"command": "set", "value": 1234567890}
Connection closed by foreign host.

抛出异常:

Traceback (most recent call last):
  File "/usr/lib/python2.7/dist-packages/twisted/python/log.py", line 84, in callWithLogger
    return callWithContext({"system": lp}, func, *args, **kw)
  File "/usr/lib/python2.7/dist-packages/twisted/python/log.py", line 69, in callWithContext
    return context.call({ILogContext: newCtx}, func, *args, **kw)
  File "/usr/lib/python2.7/dist-packages/twisted/python/context.py", line 118, in callWithContext
    return self.currentContext().callWithContext(ctx, func, *args, **kw)
  File "/usr/lib/python2.7/dist-packages/twisted/python/context.py", line 81, in callWithContext
    return func(*args,**kw)
--- <exception caught here> ---
  File "/usr/lib/python2.7/dist-packages/twisted/internet/selectreactor.py", line 146, in _doReadOrWrite
    why = getattr(selectable, method)()
  File "/usr/lib/python2.7/dist-packages/twisted/internet/tcp.py", line 460, in doRead
    rval = self.protocol.dataReceived(data)
  File "./server.py", line 18, in dataReceived
    self.factory.handle[request['command']](**request)
exceptions.TypeError: handle_set() takes exactly 1 argument (0 given)

我不明白。line 可能有问题,但我认为它是正确的 - 它隐式self.factory.handle[request['command']](**request)传递参数(毕竟这是一个方法)并显式解包请求参数。self异常消息说该函数需要 1 个参数,这是一个谎言 :) 因为它需要 2 个参数:self, **kwargs. 我传递了 0 个参数是不正确的,因为我传递了 2 个。

有人可以帮我发现问题吗?


如果有帮助,json 请求将被解码为:

{u'command': u'set', u'value': 1234567890}
4

1 回答 1

4

就像现在一样,这些handle_*方法是实例方法,但handledict 指向未绑定的方法。也就是说,self没有被隐式传递。试试这个:

class CacheFactory(protocol.Factory):
    def buildProtocol(self, addr):
        return Cache(self)
    def handle_get(self, **kwargs):
        print 'get\n', kwargs
    def handle_set(self, **kwargs):
        print 'set\n', kwargs
    def handle_delete(self, **kwargs):
        print 'delete\n', kwargs
    def __init__(self, *args, **kwargs):
        protocol.Factory.__init__(self, *args, **kwargs)
        self.handle = {
            'get': self.handle_get,
            'set': self.handle_set,
            'delete': self.handle_delete,
        }

或者,您可以保持handle不变并执行以下操作:

    def dataReceived(self, data):
        request = json.loads(data)
        self.factory.handle[request['command']](self.factory, **request)
        self.transport.write(data)

或者,您可以采用这种方法,然后您就不需要handledict 任何一种方式:

    def dataReceived(self, data):
        request = json.loads(data)
        getattr(self.factory, "handle_%s" % (request['command'],))(**request)
        self.transport.write(data)

另请注意,您dataReceived现在的 . 是不安全的,因为数据包可能会被任意拆分 - 也就是说,您可能不会一次收到完整的json消息。

于 2013-10-17T19:09:48.353 回答