View difference between Paste ID: bUnXgbCA and
SHOW:
|
|
- or go back to the newest paste.
1 | - | |
1 | + | # This is the Twisted Get Poetry Now! client, version 1.0. |
2 | ||
3 | # NOTE: This should not be used as the basis for production code. | |
4 | # It uses low-level Twisted APIs as a learning exercise. | |
5 | ||
6 | import datetime, errno, optparse, socket | |
7 | ||
8 | from twisted.internet import main | |
9 | ||
10 | ||
11 | def parse_args(): | |
12 | usage = """usage: %prog [options] [hostname]:port ... | |
13 | ||
14 | This is the Get Poetry Now! client, Twisted version 1.0. | |
15 | Run it like this: | |
16 | ||
17 | python get-poetry.py port1 port2 port3 ... | |
18 | ||
19 | If you are in the base directory of the twisted-intro package, | |
20 | you could run it like this: | |
21 | ||
22 | python twisted-client-1/get-poetry.py 10001 10002 10003 | |
23 | ||
24 | to grab poetry from servers on ports 10001, 10002, and 10003. | |
25 | ||
26 | Of course, there need to be servers listening on those ports | |
27 | for that to work. | |
28 | """ | |
29 | ||
30 | parser = optparse.OptionParser(usage) | |
31 | ||
32 | _, addresses = parser.parse_args() | |
33 | ||
34 | if not addresses: | |
35 | print parser.format_help() | |
36 | parser.exit() | |
37 | ||
38 | def parse_address(addr): | |
39 | if ':' not in addr: | |
40 | host = '' | |
41 | port = addr | |
42 | else: | |
43 | host, port = addr.split(':', 1) | |
44 | ||
45 | if not port.isdigit(): | |
46 | parser.error('Ports must be integers.') | |
47 | ||
48 | return host, int(port) | |
49 | ||
50 | return map(parse_address, addresses) | |
51 | ||
52 | ||
53 | class PoetrySocket(object): | |
54 | ||
55 | poem = '' | |
56 | ||
57 | def __init__(self, task_num, address): | |
58 | self.task_num = task_num | |
59 | self.address = address | |
60 | self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | |
61 | try: | |
62 | self.sock.connect(address) | |
63 | except: | |
64 | pass | |
65 | ||
66 | self.sock.setblocking(0) | |
67 | ||
68 | # tell the Twisted reactor to monitor this socket for reading | |
69 | from twisted.internet import reactor | |
70 | reactor.addReader(self) | |
71 | ||
72 | def fileno(self): | |
73 | try: | |
74 | return self.sock.fileno() | |
75 | except socket.error: | |
76 | return -1 | |
77 | ||
78 | def connectionLost(self, reason): | |
79 | self.sock.close() | |
80 | ||
81 | # stop monitoring this socket | |
82 | from twisted.internet import reactor | |
83 | reactor.removeReader(self) | |
84 | ||
85 | # see if there are any poetry sockets left | |
86 | for reader in reactor.getReaders(): | |
87 | if isinstance(reader, PoetrySocket): | |
88 | return | |
89 | ||
90 | reactor.stop() # no more poetry | |
91 | ||
92 | def doRead(self): | |
93 | bytes = '' | |
94 | ||
95 | while True: | |
96 | try: | |
97 | bytes += self.sock.recv(1024) | |
98 | if not bytes: | |
99 | break | |
100 | except socket.error, e: | |
101 | if e.args[0] == errno.EWOULDBLOCK: | |
102 | break | |
103 | return main.CONNECTION_LOST | |
104 | ||
105 | if not bytes: | |
106 | print 'Task %d finished' % self.task_num | |
107 | return main.CONNECTION_DONE | |
108 | else: | |
109 | msg = 'Task %d: got %d bytes of poetry from %s' | |
110 | print msg % (self.task_num, len(bytes), self.format_addr()) | |
111 | ||
112 | self.poem += bytes | |
113 | ||
114 | def logPrefix(self): | |
115 | return 'poetry' | |
116 | ||
117 | def format_addr(self): | |
118 | host, port = self.address | |
119 | return '%s:%s' % (host or '127.0.0.1', port) | |
120 | ||
121 | ||
122 | def poetry_main(): | |
123 | addresses = parse_args() | |
124 | ||
125 | start = datetime.datetime.now() | |
126 | ||
127 | sockets = [PoetrySocket(i + 1, addr) for i, addr in enumerate(addresses)] | |
128 | ||
129 | from twisted.internet import reactor | |
130 | reactor.run() | |
131 | ||
132 | elapsed = datetime.datetime.now() - start | |
133 | ||
134 | for i, sock in enumerate(sockets): | |
135 | print 'Task %d: %d bytes of poetry' % (i + 1, len(sock.poem)) | |
136 | ||
137 | print 'Got %d poems in %s' % (len(addresses), elapsed) | |
138 | ||
139 | ||
140 | if __name__ == '__main__': | |
141 | poetry_main() |