Twisted / Amp网络:响应所有客户,而不仅仅是提出请求的客户

时间:2012-10-24 20:47:56

标签: python networking twisted multiplayer

我正在努力学习这些新奇的“工厂”式网络库。 Twisted带来了很多赞誉,但对我来说绝对是一场噩梦,因为我不熟悉lambda,因此我真的不确定如何遵循演示代码所做的事情。

演示客户端:

from twisted.internet import reactor, defer
from twisted.internet.protocol import ClientCreator
from twisted.protocols import amp
from ampserver import Sum, Divide


def doMath():
    d1 = ClientCreator(reactor, amp.AMP).connectTCP(
        '127.0.0.1', 1234).addCallback(
            lambda p: p.callRemote(Sum, a=13, b=81)).addCallback(
                lambda result: result['total'])
    def trapZero(result):
        result.trap(ZeroDivisionError)
        print "Divided by zero: returning INF"
        return 1e1000
    d2 = ClientCreator(reactor, amp.AMP).connectTCP(
        '127.0.0.1', 1234).addCallback(
            lambda p: p.callRemote(Divide, numerator=1234,
                                   denominator=0)).addErrback(trapZero)
    def done(result):
        print 'Done with math:', result
    defer.DeferredList([d1, d2]).addCallback(done)

if __name__ == '__main__':
    doMath()
    reactor.run()

演示服务器:

from twisted.protocols import amp

class Sum(amp.Command):
    arguments = [('a', amp.Integer()),
                 ('b', amp.Integer())]
    response = [('total', amp.Integer())]


class Divide(amp.Command):
    arguments = [('numerator', amp.Integer()),
                 ('denominator', amp.Integer())]
    response = [('result', amp.Float())]
    errors = {ZeroDivisionError: 'ZERO_DIVISION'}


class Math(amp.AMP):
    def sum(self, a, b):
        total = a + b
        print 'Did a sum: %d + %d = %d' % (a, b, total)
        return {'total': total}
    Sum.responder(sum)

    def divide(self, numerator, denominator):
        result = float(numerator) / denominator
        print 'Divided: %d / %d = %f' % (numerator, denominator, result)
        return {'result': result}
    Divide.responder(divide)


def main():
    from twisted.internet import reactor
    from twisted.internet.protocol import Factory
    pf = Factory()
    pf.protocol = Math
    reactor.listenTCP(1234, pf)
    print 'started'
    reactor.run()

if __name__ == '__main__':
    main()

根据我的理解,客户p.callRemote(Sum, a=13, b=81)p.callRemote(Divide, numerator=1234, denominator=0)部分会调用Math.sum(13, 81)Math.Divide(1234, 0),因为工厂对象的protocol设置为{{ 1}}类。不知何故,当客户端从服务器收到返回值时,调用子函数Math,将内容输出到屏幕。

这很棒,但我的理解很糟糕,每一篇文档似乎都期待这种理解水平。

我真正希望能够做的是将数据从客户端发送到服务器,从服务器发送到连接的多个客户端。交换结束后,此方法似乎忘记了客户端,并且Done(result)阻止客户端,阻止它进行任何其他工作。

人们可能希望每一天都能使用此功能。我怎么理解这个?

编辑:我试图为客户端调用一个“签入”功能,但这似乎只是为了响应“没有报告”而将我的服务器淹没在请求中。此外,它增加了延迟,因为客户端只在需要时才接收新数据,而不是实际可用时。工厂 - 反应堆布局似乎没有暴露我需要存储的客户信息,以便随意响应它们。

1 个答案:

答案 0 :(得分:1)

您似乎有三个问题:

  1. lambda在Python中意味着什么?”

    哪个是covered by Python's documentation。如果您仍然很难阅读以这种方式编写的代码,您可以使用lambda x: y只是编写def my_function(x): return y的快捷方式这一事实。您看到lambda的任何地方,例如:

    def foo(bar):
        return boz().addCallback(lambda result: qux(bar, result))
    

    你总是可以将lambda拉出到自己的功能中,这样你就可以更容易阅读,如下所示:

    def foo(bar):
        def callback_for_boz(result):
            return qux(bar, result)
        return boz().addCallback(callback_for_boz)
    
  2. How do I make input on one connection result in output on another?

    哪个是documented by Twisted's FAQ

  3. How do I make Twisted talk to multiple clients / connect to multiple servers?

    哪个是also a twisted FAQ。这里的一般想法是reactor.run()表示“......然后运行整个程序”。在reactor.run()之前运行任何代码的唯一原因是设置初始计时器,监听套接字或第一个连接。您可以在运行反应堆之前或在程序中稍后发生的任何回调中,根据需要多次拨打connectTCPlistenTCP