扭曲延迟回调中的奇怪行为

时间:2011-09-17 17:10:04

标签: python callback twisted

目标:尝试TCP连接到服务器列表并打印如果连接成功并提示输入密码

问题:似乎我的回调(名为已连接)和errback(名为失败)中的语句(to_check -= 1)从未被执行,甚至虽然这些函数中的print语句是。

from twisted.internet import protocol, defer
import sys

class myProto(protocol.Protocol):
    got = ''
    def dataReceived(self,data):
        #print data
        self.got += data
        if "Password:" in data:
            self.transport.loseConnection()

    def connectionLost(self,reason):
        #print self.got
        if "Password:" in self.got:
            self.factory.success("and was prompted for password")
        else:
            self.factory.success("But was not prompted for password")

class myFactory(protocol.ClientFactory):
    protocol = myProto

    def __init__(self,deferred,host):
        self.deferred = deferred
        self.host = host
        print "Trying Connection to %s ..." % host

    def success(self,askpass):
        if self.deferred is not None:
            d, self.deferred = self.deferred , None
            d.callback([self.host,askpass])

    def clientConnectionFailed(self, connector, reason):
        if self.deferred is not None:
            d, self.deferred = self.deferred, None
            d.errback(reason)

def check_conn(host, port):
    from twisted.internet import reactor
    d = defer.Deferred()
    factory = myFactory(d,host)
    reactor.connectTCP(host,port,factory)
    return d

def main():

    ip = "10.1.1."
    port = 23
    total = 10
    to_check = total
    from twisted.internet import reactor
    def connected(whathappened):
        print >>sys.stdout, "Successfully connected to %s %s" % (whathappened[0],whathappened[1])
        to_check -= 1

    def failed(reason):
        print >>sys.stderr, "Connection to failed : %s" % reason
        to_check -= 1

    def checked(_):
        print >>sys.stdout, "%d connections left to check" % to_check
        if to_check == 0:
            reactor.stop()

    for i in range(0,total):
        d = check_conn(ip + str(i),port)
        d.addCallbacks(connected,failed)
        d.addBoth(checked)

    reactor.run()

if __name__ == "__main__":
    main()

输出:

Trying Connection to 10.1.1.0 ...
...
...
Trying Connection to 10.1.1.9 ...
Successfully connected to 10.1.1.1 and was prompted for password
10 connections left to check
Successfully connected to 10.1.1.0 and was prompted for password
10 connections left to check
Successfully connected to 10.1.1.2 and was prompted for password
10 connections left to check
Successfully connected to 10.1.1.9 and was prompted for password
10 connections left to check
....{Similar output}
Successfully connected to 10.1.1.6 and was prompted for password
10 connections left to check

要检查的连接数应该减少,但它保持不变。

1 个答案:

答案 0 :(得分:8)

这是你理解python中闭包的一个普遍问题;默认情况下,变量是分配它们的最内层函数的本地变量。 -=是隐式分配,因此to_check成为connectedfailed的本地变量。因此,to_check函数中的main永远不会更改。在python 3.x中,nonlocal to_checkconnected顶部的failed会让它达到预期效果。这是一个如何使用2.x中的变异完成同样的事情的例子:

import itertools

def main():

    ip = "10.1.1."
    port = 23
    to_check = 10
    counter = itertools.count().next
    from twisted.internet import reactor
    def connected(whathappened):
        print >>sys.stdout, "Successfully connected to %s %s" % (whathappened[0],whathappened[1])
        return counter()

    def failed(reason):
        print >>sys.stderr, "Connection to failed : %s" % reason
        return counter()

    def checked(count):
        print >>sys.stdout, "%d connections left to check" % (to_check - count,)
        if count == to_check:
            reactor.stop()

    for i in range(0,total):
        d = check_conn(ip + str(i),port)
        d.addCallbacks(connected,failed)
        d.addBoth(checked)

    reactor.run()