Jean-Paul,
Thanks a lot. The code is working. The python twisted is new to me too.
Here are my three more questions:
1. Since the code need to be started in a wxpyhon GUI (either by
clicking a button or up with the GUI), do I have to run the code in a
thread (sorry, I have not tried it yet)?
2. How can I grab the client data in the code? Can you write two lines
for that? I really appreciate that.
3. After I change
self.transport.write(''.join(self.data))
to
self.transport.write(''.join(data))
and scan all the ports with the following code twice (run twice).
First round scanning says "succefully connected". But second round
scanning says "failed". I have to restart your demo code to make it
work.
Ouyang
import sys, threading, socket
class scanner(threading.Thread):
tlist = [] # list of all current scanner threads
maxthreads = int(sys.argv[2]) # max number of threads we're
allowing
evnt = threading.Event() # event to signal OK to create more
threads
lck = threading.Lock() # lock to guard tlist
def __init__(self,tn,host):
threading.Thread.__init__(self)
#self.threadnum = tn # thread ID/port number
self.threadnum = 2000+tn # thread ID/port number
self.host = host # checking ports on this host
def run(self):
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
try:
s.connect((self.host, self.threadnum))
print "%d: successfully connected" % self.threadnum
s.close()
except:
print "%d: connection failed" % self.threadnum
# thread is about to exit; remove from list, and signal OK if we
# had been up against the limit
scanner.lck.acquire()
scanner.tlist.remove(self)
print "%d: now active --" % self.threadnum, scanner.tlist
if len(scanner.tlist) == scanner.maxthreads-1:
scanner.evnt.set()
scanner.evnt.clear()
scanner.lck.release()
def newthread(pn,hst):
scanner.lck.acquire()
sc = scanner(pn,hst)
scanner.tlist.append(sc)
scanner.lck.release()
sc.start()
print "%d: starting check" % pn
print "%d: now active --" % pn, scanner.tlist
newthread = staticmethod(newthread)
def main():
host = sys.argv[1]
#for i in range(1,100):
for i in range(20):
scanner.lck.acquire()
print "%d: attempting check" % i
# check to see if we're at the limit before starting a new thread
if len(scanner.tlist) >= scanner.maxthreads:
# too bad, need to wait until not at thread limit
print "%d: need to wait" % i
scanner.lck.release()
scanner.evnt.wait()
else:
scanner.lck.release()
scanner.newthread(i,host)
for sc in scanner.tlist:
sc.join()
if __name__ == '__main__':
main()
Jean-Paul Calderone 写道:
On 12 Aug 2006 09:00:02 -0700, zxo102 <zx****@gmail.comwrote:
Hi,
I am doing a small project using socket server and thread in python.
This is first time for me to use socket and thread things.
Here is my case. I have 20 socket clients. Each client send a set
of sensor data per second to a socket server. The socket server will
do two things: 1. write data into a file via bsddb; 2. forward the data
to a GUI written in wxpython.
I am thinking the code should work as follow (not sure it is
feasible)
20 threads, each thread takes care of a socket server with a
different port.
I want all socket servers start up and wait for client connection.
In the attached demo code, It stops at the startup of first socket
server somewhere in the following two lines and waits for client call:
Threads aren't the best way to manage the concurrency present in this
application. Instead, consider using non-blocking sockets with an
event notification system. For example, using Twisted, your program
might look something like this:
from twisted.internet import reactor, protocol, defer
class CumulativeEchoProtocol(protocol.Protocol):
def connectionMade(self):
# Stop listening on the port which accepted this connection
self.factory.port.stopListening()
# Set up a list in which to collect the bytes which we receive
self.received = []
def connectionLost(self, reason):
# Notify the main program that this connection has been lost, so
# that it can exit the process when there are no more connections.
self.factory.onConnectionLost.callback(self)
def dataReceived(self, data):
# Accumulate the new data in our list
self.received.append(data)
# And then echo the entire list so far back to the client
self.transport.write(''.join(self.data))
def allConnectionsLost():
# When all connections have been dropped, stop the reactor so the
# process can exit.
reactor.stop()
def main():
# Set up a list to collect Deferreds in. When all of these Deferreds
# have had callback() invoked on them, the reactor will be stopped.
completionDeferreds = []
for i in xrange(20):
# Make a new factory for this port
f = protocol.ServerFactory()
# Make a Deferred for this port's connection-lost event and make
# it available to the protocol by way of the factory.
d = defer.Deferred()
f.onConnectionLost = d
completionDeferreds.append(d)
f.protocol = CumulativeEchoProtocol
# Start listening on a particular port number with this factory
port = reactor.listenTCP(2000 + i + 1, f)
# Make the port object available to the protocol as well, so that
# it can be shut down when a connection is made.
f.port = port
# Create a Deferred which will only be called back when all the other
# Deferreds in this list have been called back.
d = defer.DeferredList(completionDeferreds)
# And tell it to stop the reactor when it fires
d.addCallback(lambda result: allConnectionsLost())
# Start the reactor so things can start happening
reactor.run()
if __name__ == '__main__':
main()
Hope this helps,
Jean-Paul