I am very new to python. I have been a very mediocre programmer, but now I have decided that I want to level up as a programmer.
I wanted to write a simple TCP client/server (where in the server acts as a simple TCP Listener). I searched on the forums and I saw that people advised using frameworks like twisted and sync.io for client server applications to take advantage of asynchronous model. But since I couldn't visualize the problems that people faced when they implemented servers as multithreaded model, so I decided to start by implementing a multithreaded server, and then improve as I go on facing issues. So I started with using socket library for both client and server: Here is my listener.py: import socket import threading from time import sleep class Serve(threading.Thread): def __init__(self, client_socket, client_address): threading.Thread.__init__(self) self.socket = client_socket self.address, self.port = client_address def run(self): try: while True: data = self.socket.recv(300) if data: print data sleep(2) else: break except Exception as e: print e finally: self.socket.close() if __name__ == '__main__': sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.bind(('localhost', 5555)) sock.listen(1) servers = [] while True: connection, client_address = sock.accept() print "New Connection from {}".format(client_address) server = Serve(connection, client_address) servers.append(server) server.start() for server in servers: server.join() Here is my sender.py. It is supposed to simulate clients connecting to the server. import argparse import socket import threading from time import sleep parser = argparse.ArgumentParser(description="A simple TCP sender") parser.add_argument('-H', '--host', help='host to connect to', default='localhost') parser.add_argument('-p', '--port', help='port of the host', type=int, default=5555) parser.add_argument('-w', '--workers', help='number of threads to create', default=1000, type=int) args = parser.parse_args() count = args.workers def send(id): lock = threading.Lock() sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server_address = (args.host, args.port) try: sock.connect(server_address) while True: sock.sendall('@ABCDEF1234567890FABC#') sleep(1) except Exception as e: print "thread no {} killed".format(id) print e lock.acquire() count-=1 lock.release() sleep(1) print "Total threads are {}".format(count) finally: sock.close() threads = [] if __name__ == '__main__': for i in range(args.workers): t = threading.Thread(target=send, args=(i,)) threads.append(t) t.start() for thread in threads: thread.join() When I run the client and server together with 1000 clients, many threads are killed on a machine with low memory, and only 210-220 clients are connected with the server. The killed clients gave the following error: `[Errno 104] Connection reset by peer` Right now I am not on the low memory machine, but I remember the error also had "broken pipe" in it. So I decided to run the same code with 1000 clients on my laptop with 8 GB memory. This time almost all clients where connected but one or two clients got killed with the same above error (I could not see broken error in the messages this time". Then I ran the same code with 500 clients, and this is where the code broke with the following errors. Exception in thread Thread-4999: Traceback (most recent call last): File "/usr/lib/python2.7/threading.py", line 810, in __bootstrap_inner File "/usr/lib/python2.7/threading.py", line 763, in run File "sender.py", line 17, in send File "/usr/lib/python2.7/socket.py", line 187, in __init__ error: [Errno 24] Too many open files Total threads are 4998 These errors came a lot, but the count said that only two threads failed. I think my logic to calculate the count is wrong. Then I decided to use SocketServer for the server. Here is the new Server: import SocketServer from threading import Thread from time import sleep class service(SocketServer.BaseRequestHandler): def handle(self): print "Client connected with ", self.client_address while True: try: data = self.request.recv(300) if data: print data sleep(2) else: print "Client exited" self.request.close() except Exception as e: print e class ThreadedTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer): pass t = ThreadedTCPServer(('localhost',5555), service) t.serve_forever() I have used the same client. This time there is some durability when there are 1000 clients, but if I disconnect the sender (send a `kill -KILL pid` signal) the listener breaks with the following error `[Errno 9] Bad file descriptor` Now if I run the sender with 5000 clients, the errors are back. Exception in thread Thread-4999: Traceback (most recent call last): File "/usr/lib/python2.7/threading.py", line 810, in __bootstrap_inner File "/usr/lib/python2.7/threading.py", line 763, in run File "sender.py", line 17, in send File "/usr/lib/python2.7/socket.py", line 187, in __init__ error: [Errno 24] Too many open files I don't even know if this is the right way of writing the servers, I also know that possibly there is something wrong with my code, and maybe I am not doing things as they are meant to be done. Is it even right to create many thousands clients using threads on the same machine? Is that what is causing problems? Should I learn some library like twisted or zmq? Would love to understand the details of threading and sockets! Please do leave your comments and criticize me. Sorry for this long post. _______________________________________________ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor