Switch branches/tags
Nothing to show
Find file Copy path
c2d4d58 Sep 25, 2012
140 lines (93 sloc) 3.64 KB
# This is the asynchronous Get Poetry Now! client.
import datetime, errno, optparse, select, socket
def parse_args():
usage = """usage: %prog [options] [hostname]:port ...
This is the Get Poetry Now! client, asynchronous edition.
Run it like this:
python port1 port2 port3 ...
If you are in the base directory of the twisted-intro package,
you could run it like this:
python async-client/ 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()
def parse_address(addr):
if ':' not in addr:
host = ''
port = addr
host, port = addr.split(':', 1)
if not port.isdigit():
parser.error('Ports must be integers.')
return host, int(port)
return map(parse_address, addresses)
def get_poetry(sockets):
"""Download poety from all the given sockets."""
poems = dict.fromkeys(sockets, '') # socket -> accumulated poem
# socket -> task numbers
sock2task = dict([(s, i + 1) for i, s in enumerate(sockets)])
sockets = list(sockets) # make a copy
# we go around this loop until we've gotten all the poetry
# from all the sockets. This is the 'reactor loop'.
while sockets:
# this select call blocks until one or more of the
# sockets is ready for read I/O
rlist, _, _ =, [], [])
# rlist is the list of sockets with data ready to read
for sock in rlist:
data = ''
while True:
new_data = sock.recv(1024)
except socket.error, e:
if e.args[0] == errno.EWOULDBLOCK:
# this error code means we would have
# blocked if the socket was blocking.
# instead we skip to the next socket
if not new_data:
data += new_data
# Each execution of this inner loop corresponds to
# working on one asynchronous task in Figure 3 here:
task_num = sock2task[sock]
if not data:
print 'Task %d finished' % task_num
addr_fmt = format_address(sock.getpeername())
msg = 'Task %d: got %d bytes of poetry from %s'
print msg % (task_num, len(data), addr_fmt)
poems[sock] += data
return poems
def connect(address):
"""Connect to the given server and return a non-blocking socket."""
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
return sock
def format_address(address):
host, port = address
return '%s:%s' % (host or '', port)
def main():
addresses = parse_args()
start =
sockets = map(connect, addresses)
poems = get_poetry(sockets)
elapsed = - start
for i, sock in enumerate(sockets):
print 'Task %d: %d bytes of poetry' % (i + 1, len(poems[sock]))
print 'Got %d poems in %s' % (len(addresses), elapsed)
if __name__ == '__main__':