python multithreaded server

13,224

Do you have two systems? Does the server system have an IP of 192.168.1.1? If you only have one system, the localhost address is 127.0.0.1. That was the first change I had to make to your code to get a connection when running the server and client on the same system.

Another issue is your client thread doesn't actually start. Since you want a client thread class, here's how to declare and start it:

  1. Subclass from threading.Thread.
  2. Override __init__ for your behavior, but call __init__ in the base class first.
  3. Override run for the thread work.
  4. Create an instance and call its start method.

Another problem is recv blocks if the client hasn't sent any data, so if you try to connect multiple clients it will hang in your loop over the client list. You'll need a thread per client or use select.select to query the client sockets for read/write readiness.

Below is the changed code that got a single client to respond, but it needs work to handle multiple clients. It also needs to set up a protocol to handle messages. TCP is a streaming protocol (no message boundaries), so a send of 'abc' and '123' could result in a receive of 'abc123' or 'ab' and 'c123', etc. It'll have to handle closing the connections and remove the client objects from the client list as well.

Good luck! You'll learn a lot figuring out how to do all this from scratch. Look at the socketserver.py library as well for example code.

srv.py

import socket
import threading
import struct
import string

class clientThread(threading.Thread):
    def __init__(self, serv):
        threading.Thread.__init__(self)
        self.server = serv
        self.clientList = []
        self.running = True
        print("Client thread created. . .")
    def run(self):
        print("Beginning client thread loop. . .")
        while self.running:
            for client in self.clientList:
                message = client.sock.recv(self.server.BUFFSIZE)
                if message != None and message != "":
                    client.update(message)

class clientObject(object):
    def __init__(self,clientInfo):
        self.sock = clientInfo[0]
        self.address = clientInfo[1]
    def update(self,message):
        self.sock.send("Testamundo.\r\n".encode())

class Server(object):
    def __init__(self):
        self.HOST = 'localhost'
        self.PORT = 22085
        self.BUFFSIZE = 1024
        self.ADDRESS = (self.HOST,self.PORT)
        self.clientList = []
        input("Press enter to start the server. . .")
        self.running = True
        self.serverSock = socket.socket()
        self.serverSock.bind(self.ADDRESS)
        self.serverSock.listen(2)
        self.clientThread = clientThread(self)
        print("Starting client thread. . .")
        self.clientThread.start()
        print("Awaiting connections. . .")
        while self.running:
            clientInfo = self.serverSock.accept()
            print("Client connected from {}.".format(clientInfo[1]))
            self.clientThread.clientList.append(clientObject(clientInfo))

        self.serverSock.close()
        print("- end -")

serv = Server()

clnt.py

import socket
import string

address = ('localhost',22085)
mySocket = socket.socket()

mySocket.connect(address)
print("Connected successfully!")
mySocket.send('blah'.encode())
print(mySocket.recv(1024))

Output (srv.py)

Press enter to start the server. . .
Client thread created. . .
Starting client thread. . .
Beginning client thread loop. . .
Awaiting connections. . .
Client connected from ('127.0.0.1', 52850).

Output (clnt.py)

Connected successfully!
b'Testamundo.\r\n'
Share:
13,224
pajm
Author by

pajm

Updated on June 19, 2022

Comments

  • pajm
    pajm almost 2 years

    What I'm trying to program is a simple multithreaded python game server for fun. After much frustration, I've not been able to figure out why my test client connection times out. Here's my server.py code:

    import socket
    import threading
    import clientThread
    import struct
    import string
    
    
    class Server:
        def __init__(self):
            self.HOST = 'localhost'
            self.PORT = 22085
            self.BUFFIZE = 1024
            self.ADDRESS = (self.HOST,self.PORT)
            self.clientList = []
            input("Press enter to start the server. . .")
            self.running = True
            self.serverSock = socket.socket()
            self.serverSock.bind(self.ADDRESS)
            self.serverSock.listen(2)
            self.clientThread = clientThread.clientThread(self)
            print("Starting client thread. . .")
            self.clientThreadObj = threading.Thread(target = self.clientThread.start, args = (self))
            print("Awaiting connections. . .")
            while self.running:
                clientInfo = self.serverSock.accept()
                print("Client connected from %s." % clientInfo[1])
                # Append to clientThread list...
    
            self.serverSock.close()
            print("- end -")
    
    
    serv = Server()
    

    The server starts the thread for existing connections and starts listening. The thread built for existing connections, clientThread, loops through a list of client objects which for now do nothing, they are simply architectural. Here is the clientThread.py

    import socket
    import threading
    import struct
    import string
    
    
    class clientThread:
        def __init__(self, serv):
            self.server = serv
            self.clientList = []
            self.running = True
            print("Client thread created. . .")
        def start(self):
            print("Beginning client thread loop. . .")
            while self.running:
                for client in self.clientList:
                    message = client.sock.recv(self.server.BUFFSIZE)
                    if message != None and message != "":
                        client.update(message)
    

    And finally, the very simple client object:

    import string
    
    
    class clientObject:
        def start(self,clientInfo):
            self.sock = clientInfo[0]
            self.address = clientInfo[1]
        def update(self,message):
            self.sock.send("Testamundo.\r\n".encode())
    

    Now, the problem here is that my client can't even connect to my server. It simply times out. Here is the code for my simple client test:

    import socket
    import string
    
    address = ("192.168.1.1",22085)
    mySocket = socket.socket()
    
    mySocket.connect(address)
    print("Connected successfully!")
    

    This returns on the line that connects to address, "A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond."

    Any suggestions? Thanks! Sorry for all this code, I wasn't sure if I needed to post it all or not, so I figured it couldn't hurt too much.