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()