Aim : To try a TCP connection to a list of server and print if the connection was successful and prompted for password or not
Problem : It seems as if a statement(to_check -= 1
) in my callback(named connected) and errback(named failed) never gets executed, even though the print statements in those functions are.
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()
Output :
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
Number of connection left to check should be decreasing, but it remains the same.
This is a general issue with your understanding of closures in python; by default, variables are local to the innermost function in which they are assigned. -=
is an implicit assignment, so to_check
becomes a local variable to connected
and failed
. As such, the to_check
in the main
function is never changed. In python 3.x, nonlocal to_check
at the top of connected
and failed
would make it do what you expect. Here's an example of how to accomplish the same thing using mutation in 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()