multithreaded tcp server python

Question:

I am trying to create a multi-threaded TCP server in python.
When a new client is accepted, it goes to a new created thread.
However, when earlier clients send data, it looks like the newly created thread intercept them, so that it look like from server side that only newer clients are speaking!

Here is my code:

Nbre = 1

class ClientThread(threading.Thread):

   def __init__(self, channel, connection):
      global Nbre
      Nbre = Nbre + 1
      print("This is thread "+str(Nbre)+" speaking")
      self.channel = channel
      self.connection = connection
      threading.Thread.__init__(self)

   def run(self):
      print(connection[0]+':'+str(connection[1])+'<'+str(Nbre)'> Connected!')
      try:
         while True:
             data = self.channel.recv(1024)
             if data:
               print(connection[0]+':'+str(connection[1])+'<'+str(Nbre)+'> '+str(data.strip('n')))
             else:
               break
      finally:
         print(connection[0]+':'+str(connection[1])+'<'+str(Nbre)+'> Exited!')
         self.channel.close()

server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server.bind(('', 4747))
server.listen(0)
while True:
   channel, connection = server.accept()
   ClientThread(channel, connection).start()

Here is what I got when launched and with telnet clients sending "Hello" for the first client, "Bonjour" for the second one :

 $ python simple_thread.py 
This is thread 2 speaking  # new connection
127.0.0.1:33925> Connected!
127.0.0.1:33925<2> hello
This is thread 3 speaking  # new connection
127.0.0.1:33926> Connected!
127.0.0.1:33926<3> Bonjour # last connected says "Bonjour" (ok here)
127.0.0.1:33926<3> hello   # first connected re-send "hello" but in thread 3?!

Why is secondly sent "hello" not poping from thread 2? And how to make it happened, so that I can reply from server side to the appropriate client?

Asked By: philippe

||

Answers:

The good news is, it probably works, but your logging is broken. Here you use Nbre, which is the number of threads, not the number of the current thread:

           print(connection[0]+':'+str(connection[1])+'<'+str(Nbre)+'> '+str(data.strip('n')))

So to make this work, store the current thread’s number on the thread object, and use that instead. Something like this:

   def __init__(self, channel, connection):
     global Nbre
     Nbre = Nbre + 1
     self.number = Nbre

There is a similar problem with the connection object. The logging is using connection instead of self.connection. Normally you’d get an error, but because the while loop at the bottom creates a global connection variable, that one gets picked up instead. So use self.connection in the logging instead.

For your own sanity, I’d also recommend extracting the logging into a function, and using string.format:

def log(self, message):
   print('{}:{}<{}> {}'.format(self.connection[0], str(self.connection[1]), self.number, message)

So you can just write self.log('Thread started') instead of repeating the log format each time.

Answered By: Thomas
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.