~ubuntu-branches/ubuntu/saucy/goldencheetah/saucy

« back to all changes in this revision

Viewing changes to src/simpleserver.py

  • Committer: Package Import Robot
  • Author(s): KURASHIKI Satoru
  • Date: 2013-08-18 07:02:45 UTC
  • mfrom: (4.1.8 sid)
  • Revision ID: package-import@ubuntu.com-20130818070245-zgdvb47e1k3mtgil
Tags: 3.0-3
debian/control: remove needless dependency. (Closes: #719571)

Show diffs side-by-side

added added

removed removed

Lines of Context:
27
27
import SocketServer
28
28
import sys
29
29
 
30
 
# this class keeps track of the state of a connected peer, including
31
 
# the socket used to talk to it, it's name, and a queue of records waiting
32
 
# to be written into it.
 
30
MAXPEERS = 4096
 
31
 
 
32
# this class keeps track of the state of a peer, including the socket
 
33
# used to talk to it, it's name, and a queue of records waiting to be
 
34
# written into it.
33
35
class PeerTracker():
34
 
    def __init__(self):
 
36
    def __init__(self, name):
35
37
        self.writequeue = [ ]   # list of records to be sent TO peer
36
 
 
37
 
# The main "threaded web server" class.  Has a condition variable and
38
 
# a list of connected peers.
 
38
        self.connected = False
 
39
        self.peername = name
 
40
 
 
41
    # scrub my state when the peer disconnects
 
42
    def clean(self):
 
43
        self.writequeue = [ ]
 
44
        self.connected = False
 
45
        self.socket = None
 
46
 
 
47
# The main "threaded server" class.  Has a condition variable and a
 
48
# dict of connected peers.
39
49
class CheetahServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
40
 
    def init_cheetah(self):
 
50
    def init_cheetah(self, maxpeers):
41
51
        self.cond = threading.Condition()   # used to coordinate client lists
42
 
        self.peers = [ ]  # a list of connected peers
 
52
        self.peers = { }  # a dict of peers
 
53
        for i in range(0, maxpeers):
 
54
            self.peers[i] = PeerTracker("Peer " + str(i))
43
55
 
44
56
# A new ThreadedCheetahHandler is instantiated for each incoming connection,
45
57
# and a new thread is dispatched to handle() to service that connection.
50
62
        self.server.cond.acquire()
51
63
        print "(" + self.me_peer.peername + ")", \
52
64
            "bogus or broken input, dropping.\n"
53
 
        self.server.peers.remove(self.me_peer)
 
65
        self.me_peer.clean()
54
66
        self.server.cond.release()
55
67
 
56
68
    # a line of data was received; this method is invoked to parse it
58
70
    # peer is killed off.  if parsing succeeds but only one peer is
59
71
    # connected, the record is dropped but the peer stays up.
60
72
    def processinput(self, data):
61
 
        # make sure data has 6 fields. if not, drop peer.
 
73
        # make sure data has 7 fields. if not, drop peer.
62
74
        components = data.split()
63
 
        if (len(components) != 6):
 
75
        if (len(components) != 7):
64
76
            self.removepeer()
65
77
            return True
66
78
        # try to parse the fields.  if fail, drop peer.
67
79
        try:
68
80
            valdict = { }
69
 
            valdict['watts'] = float(components[0])
70
 
            valdict['hr'] = float(components[1])
71
 
            valdict['time'] = int(components[2])
72
 
            valdict['speed'] = float(components[3])
73
 
            valdict['rpm'] = float(components[4])
74
 
            valdict['load'] = float(components[5])
 
81
            valdict['peername'] = components[0]
 
82
            valdict['watts'] = float(components[1])
 
83
            valdict['hr'] = float(components[2])
 
84
            valdict['time'] = int(components[3])
 
85
            valdict['speed'] = float(components[4])
 
86
            valdict['rpm'] = float(components[5])
 
87
            valdict['load'] = float(components[6])
75
88
 
76
89
            # parse succeeded, so add to peer's input queue
77
90
            print "(" + self.me_peer.peername + ")", \
78
91
                "well-formed record arrived..."
79
 
            print "  ... watts:%.2f hr:%.2f time:%ld speed:%.2f rpm:%.2f load:%.3f" % \
80
 
                (valdict['watts'], valdict['hr'], valdict['time'], \
 
92
            print "  ... name:%s watts:%.2f hr:%.2f time:%ld speed:%.2f rpm:%.2f load:%.3f" % \
 
93
                (valdict['peername'], valdict['watts'], valdict['hr'], valdict['time'], \
81
94
                     valdict['speed'], valdict['rpm'], valdict['load'])
82
95
            self.server.cond.acquire()
83
 
            if (len(self.server.peers) == 2):
84
 
                if (self.server.peers[0] == self.me_peer):
85
 
                    otherpeer = self.server.peers[1]
86
 
                else:
87
 
                    otherpeer = self.server.peers[0]
88
 
                otherpeer.writequeue.append(valdict)
89
 
 
 
96
            numqueued = 0
 
97
            for i in range(0, len(self.server.peers)):
 
98
                if (not (self.server.peers[i] == self.me_peer)) and (self.server.peers[i].connected):
 
99
                    self.server.peers[i].writequeue.append(valdict)
 
100
                    print "  ...queued for", self.server.peers[i].peername + "\n"
 
101
                    numqueued = numqueued + 1
 
102
            if numqueued > 0:
90
103
                # notify writing thread that there is work to do
91
104
                self.server.cond.notify()
92
 
                print "  ...queued for", otherpeer.peername + "\n"
93
105
            else:
94
 
                print "  ...but other peer not connected,", \
 
106
                print "  ...but no other peers are connected,", \
95
107
                    "so dropped it.\n"
96
108
            self.server.cond.release()
97
109
        except ValueError:
112
124
        print "(server) new incoming connection..."
113
125
        self.server.cond.acquire()
114
126
        # If the server is full, bonk out, else add.
115
 
        if (len(self.server.peers) < 2):
116
 
            # We have room.  Create record for new peer.
117
 
            self.me_peer = PeerTracker()
118
 
            self.me_peer.socket = self.request
119
 
            if (len(self.server.peers) == 0):
120
 
                self.me_peer.peername = "Peer A"
121
 
            elif (self.server.peers[0].peername == "Peer A"):
122
 
                self.me_peer.peername = "Peer B"
123
 
            else:
124
 
                self.me_peer.peername = "Peer A"
125
 
            self.server.peers.append(self.me_peer)
126
 
            print "  ...added peer #", str(len(self.server.peers)), \
127
 
                "named \"" + self.me_peer.peername + "\"\n"
128
 
            done = False
129
 
        else:
 
127
        addedpeer = False
 
128
        for i in range(0, len(self.server.peers)):
 
129
            if (not addedpeer) and (self.server.peers[i].connected == False):
 
130
                # We have room.  Create record for new peer in slot i
 
131
                self.me_peer = self.server.peers[i]
 
132
                self.me_peer.connected = True
 
133
                self.me_peer.socket = self.request
 
134
                print "  ...connected " + self.me_peer.peername + "\n"
 
135
                addedpeer = True
 
136
                done = False
 
137
        if addedpeer == False:
130
138
            # Server is full, so bonk out.
131
 
            print "  ...but server already has 2 peers, so dropping.\n"
 
139
            print "  ...but server already has max peers, so dropping.\n"
132
140
            done = True
133
141
        self.server.cond.release()
134
142
 
137
145
        while not done:
138
146
            try:
139
147
                data = socketfile.readline()
 
148
                print '[debug][' + self.me_peer.peername + '] got: \"' + data + '\"\n'
140
149
                done = self.processinput(data)
141
150
            except socket.error, msg:
142
151
                self.removepeer()
146
155
# record into a peer's socket.  if the write fails, we ignore for now,
147
156
# and rely on the read on the socket to fail and clean up later.
148
157
def write_to_peer(item, peer):
149
 
    s = "%.2f %.2f %d %.2f %.2f %.3f\n" % \
150
 
        (item['watts'], item['hr'], item['time'], \
 
158
    s = "%s %.2f %.2f %d %.2f %.2f %.3f\n" % \
 
159
        (item['peername'], item['watts'], item['hr'], item['time'], \
151
160
             item['speed'], item['rpm'], item['load'])
152
161
    try:
153
162
        peer.socket.sendall(s)
168
177
    while True:
169
178
        server.cond.wait()
170
179
        # see if the first peer has some work
171
 
        for peer in server.peers:
 
180
        for peer in server.peers.itervalues():
172
181
            while len(peer.writequeue) > 0:
173
182
                next = peer.writequeue.pop(0)
174
183
                write_to_peer(next, peer)
175
184
    server.cond.release()
176
185
 
177
 
# main() invokes this to spawn the web server and the writer thread.
178
 
def run_server(port):
179
 
    # initialize the web server
 
186
# main() invokes this to spawn the server and the writer thread.
 
187
def run_server(port, maxpeers):
 
188
    # initialize the server
180
189
    server = CheetahServer(("", port), ThreadedCheetahHandler)
181
190
    server.allow_reuse_address = True
182
191
    ip, port = server.server_address
183
192
    print "(server) running in thread:", \
184
193
        threading.currentThread().getName() + "\n"
185
 
    server.init_cheetah()
 
194
    server.init_cheetah(maxpeers)
186
195
 
187
196
    # fire up the writer thread
188
197
    writer_thread = threading.Thread(target=thread_write, args=(server,))
198
207
###############################
199
208
 
200
209
def usage():
201
 
    print "usage: ./simpleserver.py listen_port"
 
210
    print "usage: ./simpleserver.py listen_port max_num_peers"
 
211
    print "   where 2 <= maxpeers < " + str(MAXPEERS) + "\n"
202
212
    sys.exit(1)   # failure
203
213
 
204
214
def main(argv):
205
215
    # validate arguments
206
 
    if (len(argv) != 1):
 
216
    if (len(argv) != 2):
207
217
        usage()
208
218
    try:
209
219
        port = int(argv[0])
 
220
        maxpeers = int(argv[1])
210
221
    except ValueError:
211
222
        usage()
212
 
    if ((port < 1) or (port > 65535)):
 
223
    if ((port < 1) or (port > 65535) or (maxpeers < 2) or (maxpeers > MAXPEERS)):
213
224
        usage()
214
225
 
215
226
    # great!
216
 
    run_server(port)
 
227
    run_server(port, maxpeers)
217
228
 
218
229
if __name__ == "__main__":
219
230
    main(sys.argv[1:])