目标:尝试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
要检查的连接数应该减少,但它保持不变。
答案 0 :(得分:8)
这是你理解python中闭包的一个普遍问题;默认情况下,变量是分配它们的最内层函数的本地变量。 -=
是隐式分配,因此to_check
成为connected
和failed
的本地变量。因此,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()