扭曲的延迟回调中的奇怪行为
目标:尝试与一系列服务器建立TCP连接,并打印出连接是否成功,以及是否提示输入密码。
问题:在我的回调函数(叫做connected)和错误回调函数(叫做failed)中,有一句代码(to_check -= 1
)似乎从来没有被执行过,尽管这些函数中的打印语句是有输出的。
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 个回答
8
这是关于你对Python中闭包理解的一般性问题;默认情况下,变量只在它被赋值的最内层函数中有效。-=
是一种隐式赋值,所以 to_check
变成了 connected
和 failed
的局部变量。因此,main
函数中的 to_check
永远不会被改变。在Python 3.x中,在 connected
和 failed
的顶部加上 nonlocal to_check
就能让它按你预期的那样工作。下面是一个在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()