Thread: Threaded Server

Page 1 of 2 12 Last
  • Jump to page:
    #1
  1. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Aug 2003
    Posts
    217
    Rep Power
    0

    Threaded Server


    I've got a simple threaded server but I don't know how to manage my threads so the server can send the input of one client to another.

    Code:
    #!/usr/bin/env python
    
    import socket
    import sys
    
    import threading
    
    class serveClient(threading.Thread):
    	def __init__(self, client, addr, tid):
    		threading.Thread.__init__(self)
    		self.client = client
    		self.addr = addr
    		self.tid = tid
    		print '%s connected' % (self.addr[0])
    		
    	def run(self):
    		while True:
    			input = self.client.recv(1)
    			if not input:
    				break
    			print '%s says: %s' % (self.addr[0], input)
    		
    		self.client.close()
    		
    class acceptClient(threading.Thread):		
    	def run(self):
    		server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    		port = int(sys.argv[1])
    		server.bind(('', port))
    		server.listen(5)
    		for tid in range(2):
    			(client, addr) = server.accept()
    			thread = serveClient(client, addr, tid)
    			thread.start()
    			
    			
    
    if __name__ == '__main__':	
    
    	server = acceptClient()
    	server.start()
  2. #2
  3. Mini me.
    Devshed Novice (500 - 999 posts)

    Join Date
    Nov 2003
    Location
    Cambridge, UK
    Posts
    783
    Rep Power
    13
    Just a few thoughts:
    You could keep track of your serveClient objects in a list.

    I guess you would need a queue to stack the incomming messages (you can get multiple incommings). If you assume all clients talk to each other, you could periodically send the messages out to them. You could just step through each object and send all the messages out en-mass, working on a copy of the queue to allow the clients to send in more messages. You will need locks on the queue to prevent problems with simultaneous access.

    No idea how it would perform tho - you have a lot to handle (e.g. blocking, exceptions, dropped conections)

    But I think twisted already have a chat type server

    Grim
  4. #3
  5. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Aug 2003
    Posts
    217
    Rep Power
    0
    So for the threads list:

    Code:
    threadlist = []      
    thread = serveClient(client, addr, tid)
    theadlist.append(thread)
    threadlist[tid].start()
    I don't think I approached this in the right way. It's going to take a bit more thinking to get it working right. I'll post back later.
  6. #4
  7. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Aug 2003
    Posts
    217
    Rep Power
    0
    I've got something a bit different now but I'm still having a few problems

    Code:
    import socket
    import sys
    
    import threading
    
    messages = []
    clientlist = []
    
    class clientReceive(threading.Thread):
    	def __init__(self, client, addr, tid):
    		threading.Thread.__init__(self)
    		self.client = client
    		self.addr = addr
    		self.tid = tid
    		
    	def run(self):
    		global messages		
    		while True:
    			msg = self.client.recv(1)
    			if msg == 0:
    				break
    			else:
    				messages.append(str(self.tid) + msg)
    		self.client.close()
    		
    class clientSend(threading.Thread):
    	def run(self):
    		global messages
    		global clientlist
    		
    		if messages:
    			for msg in messages:
    				current = msg[0] # Not used atm.
    				del msg[0]
    				for client in clientlist:
    					client.client.send(char(msg))
    				
    
    if __name__ == '__main__':	
    	server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    	port = int(sys.argv[1])
    	server.bind(('', port))
    	server.listen(5)
    	
    	thread = clientSend()
    	thread.start()
    	
    	for tid in range(2):
    		(client, addr) = server.accept()
    		print '%s connected' % (addr[0])
    		thread = clientReceive(client, addr, tid)
               thread.start()
    		clientlist.append(thread)
    For some reason run() in clientSend doesn't ever send info. From what I can tell, it never even makes it past the 'if messages: ' bit.
  8. #5
  9. Mini me.
    Devshed Novice (500 - 999 posts)

    Join Date
    Nov 2003
    Location
    Cambridge, UK
    Posts
    783
    Rep Power
    13
    Xx,
    The clientSend thread will terminate as soon as the message list is empty. At the beginning the list is empty so it terminates straight away.

    That thread need to stay alive - maybe a while loop in the thread.
    Code:
    while OK_to_run:
        If messages:
             .......
        #and put thread on hold until something happens
    Last edited by Grim Archon; March 3rd, 2004 at 05:34 PM.
  10. #6
  11. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Aug 2003
    Posts
    217
    Rep Power
    0
    OMG! I knew it would be something silly like that! Thanks .
  12. #7
  13. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Aug 2003
    Posts
    217
    Rep Power
    0
    I have most of the multithreading stuff fixed now but I'm not sure how to implement proper message sending/receiving. At the moment I'm only passing chars (1 byte) around. How do I accommodate for abitrary length messages?

    EDIT: btw, are globals the only way to communicate in between threads?

    Thanks in advance .
    Last edited by XxChris; March 4th, 2004 at 10:57 AM.
  14. #8
  15. Mini me.
    Devshed Novice (500 - 999 posts)

    Join Date
    Nov 2003
    Location
    Cambridge, UK
    Posts
    783
    Rep Power
    13
    self.client.recv(1024) will recieve upto 1024 bytes but returns as soon as there is no data left to read or the maximum is reached.

    The Queue module should help as it is designed for inter-thread communication. You will probably need one per connection for receiving message but you could even have a second for sending. The advantage here is that it handles the locking for you

    You will probably need to handle the empty/full exceptions.

    Does your sender terminate too soon?

    Grim
  16. #9
  17. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Aug 2003
    Posts
    217
    Rep Power
    0
    Thanks, I will look into that module. I'm going to continue to mess with this for a while until I'm satisfied for the moment. I'll then post it here.
  18. #10
  19. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Aug 2003
    Posts
    217
    Rep Power
    0
    Ok all the send stuff is working properly, but I'm having trouble getting the server to quit prematurely. What is a good way to get all the threads to quit? I've tryed a few ways without much luck .
  20. #11
  21. Mini me.
    Devshed Novice (500 - 999 posts)

    Join Date
    Nov 2003
    Location
    Cambridge, UK
    Posts
    783
    Rep Power
    13
    I'm sure there are other (read 'better') ways but try replacing the While True: with While global_run_variable:
    Then you can use the global variable to tell the threads to finish. If you declare the name as global in the threading class then any of your threads could change it to False. As the only time the variable changes state will be to go from True to False there is no worry about racing values. Having more than one thread doing the same thing only results in the value going to False.

    WRT to your earlier question - threads share the same global namespace so there is really no other way for them to communicate other than complicated pipes or sockets. This is why locks were created for situations where multiple threads influence globally accessable values. The Queue module wraps global standard objects and hides the complexity for you.

    You could/should use the join() method to make sure things have shut down before the main thread moves on to other things.

    If this idea is not satisfactory then you could consider re-writting the code to use select and then you can enforce time out conditions.

    Grim
  22. #12
  23. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Aug 2003
    Posts
    217
    Rep Power
    0
    I already tryed the global_run idea but if a socket is blocking on a recv() it doesn't turn out too well .
  24. #13
  25. Mini me.
    Devshed Novice (500 - 999 posts)

    Join Date
    Nov 2003
    Location
    Cambridge, UK
    Posts
    783
    Rep Power
    13
    If you are running Python 2.3 then the socket module supports new functions:

    socket.setdefaulttimeout( timeout)
    if you use setdefaulttimeout(0.1) then the recv should timeout within 100 msec.

    Also you can set the socket object to non-blocking:
    socket_object.setblocking( False)
    and set timeout values
    socket_object.settimeout( 0.1)

    That will allow your loops to continue.
    Note: if the recv and send functions return without doing anything they raise a socket error exception.

    Plenty to experiment with.


    Grim
  26. #14
  27. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Aug 2003
    Posts
    217
    Rep Power
    0
    Ahh cool thanks .
  28. #15
  29. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Aug 2003
    Posts
    217
    Rep Power
    0
    Grrr, another problem. This one just doesn't make sense to me. I run threading.currentThread() and I get the thread object of the thread that created the thread that is calling it (currentThread()).

    EDIT: Turns out if I don't place it in the class constructor it works . Anybody know why this happens?
    Last edited by XxChris; March 6th, 2004 at 04:35 PM.
Page 1 of 2 12 Last
  • Jump to page:

IMN logo majestic logo threadwatch logo seochat tools logo