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

viv*_*vek 2 python twisted callback

目标:尝试与服务器列表建立TCP连接,并在连接成功并提示输入密码时进行打印

问题:似乎to_check -= 1我的回调(名为connected)和errback(名为failed)中的statement()永远不会被执行,即使这些函数中的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()
Run Code Online (Sandbox Code Playgroud)

输出:

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
Run Code Online (Sandbox Code Playgroud)

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

hab*_*bit 8

这是你理解python中闭包的一个普遍问题; 默认情况下,变量是分配它们的最内层函数的本地变量.-=是隐式分配,所以to_check成为局部变量connectedfailed.因此,函数to_check中的main函数永远不会改变.在python 3.x中,nonlocal to_check在顶部,connected并将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()
Run Code Online (Sandbox Code Playgroud)