-
-
Save alpha-beta-soup/37e47fa6ddccd3bb733f to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# This is the Twisted Get Poetry Now! client, version 1.0. | |
# NOTE: This should not be used as the basis for production code. | |
# It uses low-level Twisted APIs as a learning exercise. | |
import datetime, errno, optparse, socket | |
from twisted.internet import main | |
def parse_args(): | |
usage = """usage: %prog [options] [hostname]:port ... | |
This is the Get Poetry Now! client, Twisted version 1.0. | |
Run it like this: | |
python get-poetry.py port1 port2 port3 ... | |
If you are in the base directory of the twisted-intro package, | |
you could run it like this: | |
python twisted-client-1/get-poetry.py 10001 10002 10003 | |
to grab poetry from servers on ports 10001, 10002, and 10003. | |
Of course, there need to be servers listening on those ports | |
for that to work. | |
""" | |
parser = optparse.OptionParser(usage) | |
_, addresses = parser.parse_args() | |
if not addresses: | |
print parser.format_help() | |
parser.exit() | |
def parse_address(addr): | |
if ':' not in addr: | |
host = '127.0.0.1' | |
port = addr | |
else: | |
host, port = addr.split(':', 1) | |
if not port.isdigit(): | |
parser.error('Ports must be integers.') | |
return host, int(port) | |
return map(parse_address, addresses) | |
class PoetrySocket(object): | |
poem = '' | |
def __init__(self, task_num, address, complete_timeout=5): | |
self.task_num = task_num | |
self.address = address | |
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | |
if self.sock.connect_ex(address) == 0: | |
self.sock.setblocking(0) | |
# tell the Twisted reactor to monitor this socket for reading | |
from twisted.internet import reactor | |
reactor.addReader(self) | |
else: | |
print "Could not connect to Task", self.task_num | |
self.timeout = reactor.callLater(complete_timeout, self.forceClose) | |
def fileno(self): | |
'''retutns the file descriptor we want to monitor''' | |
try: | |
return self.sock.fileno() | |
except socket.error: | |
return -1 | |
def forceClose(self): | |
self.connectionLost('Poem did not complete in allowed timeframe') | |
def connectionLost(self, reason=None): | |
'''when the connection is closed''' | |
self.sock.close() | |
# stop monitoring this socket | |
from twisted.internet import reactor | |
print "Reactor no longer monitored: %s" % reason | |
reactor.removeReader(self) | |
# see if there are any poetry sockets left | |
for reader in reactor.getReaders(): | |
if isinstance(reader, PoetrySocket): | |
return | |
reactor.stop() # no more poetry | |
def doRead(self): | |
''' | |
needed for addReader: any argument of that function needs to implement | |
the IReadDescriptor interface. | |
''' | |
bytes = '' | |
while True: | |
try: | |
bytesread = self.sock.recv(1024) | |
if not bytesread: | |
break | |
else: | |
bytes += bytesread | |
except socket.error, e: | |
if e.args[0] == errno.EWOULDBLOCK: | |
break | |
return main.CONNECTION_LOST | |
if not bytes: | |
print 'Task %d finished' % self.task_num | |
self.timeout.cancel() | |
return main.CONNECTION_DONE | |
else: | |
msg = 'Task %d: got %d bytes of poetry from %s' | |
print msg % (self.task_num, len(bytes), self.format_addr()) | |
self.poem += bytes | |
def logPrefix(self): | |
'''we need to implmenet ILoggingContext, as IFileDescriptor inherits | |
from it''' | |
return 'poetry' | |
def format_addr(self): | |
host, port = self.address | |
return '%s:%s' % (host or '127.0.0.1', port) | |
def poetry_main(): | |
addresses = parse_args() | |
start = datetime.datetime.now() | |
sockets = [PoetrySocket(i + 1, addr) for i, addr in enumerate(addresses)] | |
from twisted.internet import reactor | |
reactor.run() | |
elapsed = datetime.datetime.now() - start | |
for i, sock in enumerate(sockets): | |
print 'Task %d: %d bytes of poetry' % (i + 1, len(sock.poem)) | |
print 'Got %d poems in %s' % (len(addresses), elapsed) | |
if __name__ == '__main__': | |
poetry_main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment