1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 """
16 COMM module
17
18 Author: Michel F. Sanner
19 Date: Oct 11 2000
20
21 This module implements the Comm class that provides bi-directional communication over sockets. The Comm object provides server functionality, accepting connections from multiple clients (each client is handled by a separate thread). the comm object also provides client side functionality, allowing a Comm object to connect to an existing server.
22
23 A - Server side
24 After a Comm object has been created, the startServer method can be called to
25 create a socket (self.serverSocket) and find a free port to which this socket
26 will be bound. The port is stored in self.port
27
28 By calling the acceptClients(func, maxConnections) one can allow the server to accept connection from clients. 'func' will be called for each message sreceived from clients. FIXME: calling func should probably set a lock.
29 acceptClients works in its own thread. When a client connects, a new thread is started to handle input from this client (listenToClient()) and the client is added to the Comm's clients dictionary.
30
31 The client dictionary uses the client's name as a key and stores the socket and the address created by accept.
32
33 hangupClient(name, client) can be called to terminate a connection with a specific client.
34
35 sendToClients(message) can be used to send a string to all connected clients
36
37 B - Client side
38
39 A comm object can be used to connect to a running server using the connectToServer(self, host, port, func). host cane be a host name or an IP address (as string). If the connection is successful a new thread is started to listen to the server and 'func' will be called with all messages comming from that server.
40
41 disconnectFromServer(self, clientSocket) can be called to disconnect fropm a server. 'clientSocket' can be a socket or a
42 """
43 import sys, time
44 from socket import *
45 import thread, types
46
48
50 self.verbose = 1
51
52
53 self.clients = {}
54
55
56
57 self.port = None
58 self.serverSocket = None
59 self.maxConnections = 5
60
61
62 self.serverSockets = {}
63
64
65
66 - def getPort(self, socket, base=50000):
67 """find the first free port above base"""
68 port = base
69 while(1):
70 try:
71 socket.bind( ( '', port))
72 return port
73 except:
74 import traceback
75 traceback.print_exc()
76 port = port + 1
77 print port
78
79
81 self.serverSocket = s = socket(AF_INET, SOCK_STREAM)
82 if port is None:
83 self.port = self.getPort(s)
84 else:
85 self.port = port
86
88 self.maxConnections = maxConnections
89 self.serverSocket.listen(maxConnections)
90 if self.verbose:
91 print "server ready, listening to port ", self.port
92 while 1:
93 conn, addr = self.serverSocket.accept()
94 name = gethostbyaddr(conn.getpeername()[0])[0] + str(addr[1])
95 self.clients[name] = ( conn, addr )
96 if self.verbose:
97 print 'Connected by', name, '\n'
98 thread.start_new(self.listenToClient, (name, conn, func))
99
101 while (1):
102 i = 0
103 data = client.recv(1024)
104 if len(data)==0:
105 if self.verbose:
106 print 'Connection closed by client'
107 self.hangupClient(client)
108 return
109 func(name, data)
110
112 if type(client) == types.StringType:
113 cl = self.clients[client][0]
114 else:
115 cl = client
116 client = None
117 for key, value in self.clients.items():
118 if value[0]==cl:
119 client = key
120 break
121 if client is None:
122 raise ValueError, "client not found"
123
124 cl.close()
125 del self.clients[client]
126
128 """send a messaqe to all clients"""
129 for c in self.clients.values():
130 c[0].send(message)
131
133 """send a messaqe to all clients"""
134 return self.clients.keys()
135
136
137
139 """become a client of a server specified using host and port,
140 func will be called to handle messages from server
141 """
142 host = gethostbyname(host)
143 serverSocket = socket(AF_INET, SOCK_STREAM)
144 serverSocket.connect( ( host, port))
145 name = gethostbyaddr(serverSocket.getpeername()[0])[0]+str(port)
146 self.serverSockets[name] = serverSocket
147 thread.start_new(self.listenToServer, (name, serverSocket, func))
148
150 while (1):
151 i = 0
152 data = client.recv(1024)
153 if len(data)==0:
154 print 'Connection closed by server'
155 self.disconnectFromServer(client)
156 return
157 func(name, data)
158
160 if type(server) == types.StringType:
161 cl = self.serverSockets[server]
162 else:
163 cl = server
164 server = None
165 for key, values in self.serverSockets.items():
166 if values==cl:
167 server = key
168 break
169 if server is None:
170 raise ValueError, "server not found"
171 cl.shutdown(2)
172 cl.close()
173 del self.serverSockets[server]
174
176 """send a messaqe to all servers"""
177 return self.serverSockets.keys()
178
179
180 if __name__ == '__main__':
181 com = Comm()
182 com.startServer()
183
184
185 - def foo1(client, data):
186 print 'client %s sent> %s'%(client,data)
187
188 thread.start_new(com.acceptClients, (foo1,))
189
190 - def foo(server, data):
191 print 'server %s sent> %s'%(server,data)
192
193
194