Python Sockets, Advanced Chat Box
<p>I want to create a server that <strong>handles</strong> a lot of clients at the same time (<strong>handles</strong>: receiving data from clients and sending data to all clients at the same time!!!)</p>

<p>Actually i'm trying to create a chat box. The program will work like this:</p>

<p>1) There's going to be a server which handles the clients. </p>

<p>2) More than one clients can join the server.</p>

<p>3) Clients send messages (Strings) to the server.</p>

<p>4) The server receive's the message from a client and then it send's it to all 
the clients except the one he got it from.</p>

<p>And this is how the clients will communicate each other. No private messages available. When someone hits the enter all the clients will see the message on their screen.</p>

<p>The client module is easy to make, because the client communicates only with one socket (The Server).</p>

<p>The server module from the other hand is really complicated, i don't know how to do it (I also know about threads).</p>

<p>This is my atempt:</p>

<pre><code>import socket, threading


class Server:

def __init__(self, ip = "", port = 5050):

    '''Server Constructor. If __init__ return None, then you can use
       self.error to print the specified error message.'''

    #Error message.
    self.error  = ""

    #Creating a socket object.
    self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    #Trying to bind it.
    try:
        self.server.bind( (ip, port) )
        pass


    #Failed, because socket has been shuted down.
    except OSError :
        self.error = "The server socket has been shuted down."
        return None

    #Failed, because socket has been forcibly reseted.
    except ConnectionResetError:
         self.error = "The server socket has been forcibly reseted."
         return None


    #Start Listening.
    self.server.listen()


    #_____Other Variables_____#

    #A flag to know when to shut down thread loops.
    self.running = True

    #Store clients here.
    self.clients = []

    #_____Other Variables_____#


    #Start accepting clients.
    thread = threading.thread(target = self.acceptClients)
    thread.start()

    #Start handling the client.
    self.clientHandler()





#Accept Clients.
def acceptClients(self):

    while self.running:
        self.clients.append( self.server.accept() )

    #Close the server.
    self.server.close()




#Handle clients.
def clientHandler(self):

    while self.running:

        for client in self.clients:

            sock = client[0]
            addr = client[1]

            #Receive at most 1 mb of data.
            #The problem is that recv will block the loop!!!
            data = sock.recv(1024 ** 2)
</code></pre>

<p>As you can see, i accept clients using a thread so the server.accept() won't block the program. And then i store the clients into a list.</p>

<p>But the problem is on the <strong>clientHandler</strong>. How am i going to recv from all
clients at the same time? The first recv will block the loop!!!</p>

<p>I also tried to start new threads (clientHandlers) for every new client
but the problem was the synchronization.</p>

<p>And what about the send? The server must send data to all the clients, so the clientHandler is not yet finished. But if i mix the methods <strong>recv</strong> and <strong>send</strong> then the problem become's more complicated. </p>

<p>So what is the proper and best way to do this?
I'd like to give me an example too.</p>

<p><em>This my final program and works like a charm.</em></p>

<p><strong>Server.py</strong></p>

<p>import socket, select</p>

<p>class Server:</p>

<pre><code>def __init__(self, ip = "", port = 5050):

    '''Server Constructor. If __init__ return None, then you can use
       self.error to print the specified error message.'''

    #Error message.
    self.error  = ""

    #Creating a socket object.
    self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    #Trying to bind it.
    try:
        self.server.bind( (ip, port) )
        pass


    #Failed, because socket has been shuted down.
    except OSError :
        self.error = "The server socket has been shuted down."

    #Failed, because socket has been forcibly reseted.
    except ConnectionResetError:
         self.error = "The server socket has been forcibly reseted."


    #Start Listening.
    self.server.listen()


    #_____Other Variables_____#

    #A flag to know when to shut down thread loops.
    self.running = True

    #Store clients here.
    self.sockets   = [self.server]

    #_____Other Variables_____#


    #Start Handling the sockets.
    self.handleSockets()






#Handle Sockets.
def handleSockets(self):

    while True:
        r, w, x = select.select(self.sockets, [], self.sockets)

        #If server is ready to accept.
        if self.server in r:

            client, address = self.server.accept()
            self.sockets.append(client)


        #Elif a client send data.
        elif len(r) &gt; 0:

            #Receive data.
            try:
                data = r[0].recv( 1024 )


            #If the client disconnects suddenly.
            except ConnectionResetError:
                r[0].close()
                self.sockets.remove( r[0] )
                print("A user has been disconnected forcible.")
                continue

            #Connection has been closed or lost.
            if len(data) == 0:

                r[0].close()
                self.sockets.remove( r[0] )
                print("A user has been disconnected.")


            #Else send the data to all users.
            else:

                #For all sockets except server.
                for client in self.sockets[1:]:

                    #Do not send to yourself.
                    if client != r[0]:
                        client.send(data)


server = Server()
print("Errors:",server.error)
</code></pre>

<p><strong>Client.py</strong></p>

<p>import socket, threading</p>

<p>from tkinter import *</p>

<p>class Client:</p>

<pre><code>def __init__(self, ip = "192.168.1.3", port = 5050):

    '''Client Constructor. If __init__ return None, then you can use
       self.error to print the specified error message.'''

    #Error message.
    self.error  = ""

    #Creating a socket object.
    self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    #Trying to bind it.
    try:
        self.server.connect( (ip, port) )
        pass


    #Failed, because socket has been shuted down.
    except OSError :
        self.error = "The client socket has been shuted down."
        return

    #Failed, because socket has been forcibly reseted.
    except ConnectionResetError:
         self.error = "The client socket has been forcibly reseted."
         return

    #Failed, because socket has been forcibly reseted.
    except ConnectionRefusedError:
         self.error = "The server socket refuses the connection."
         return


    #_____Other Variables_____#

    #A flag to know when to shut down thread loops.
    self.running = True

    #_____Other Variables_____#



#Start the GUI Interface.
def startGUI(self):

    #Initialiazing tk.
    screen = Tk()
    screen.geometry("200x100")

    #Tk variable.
    self.msg = StringVar()

    #Creating widgets.
    entry  = Entry( textvariable = self.msg )
    button = Button( text = "Send", command = self.sendMSG )

    #Packing widgets.
    entry.pack()
    button.pack()

    screen.mainloop()



#Send the message.
def sendMSG(self):
    self.server.send( str.encode( self.msg.get() ) )



#Receive message.
def recvMSG(self):

    while self.running:

        data = self.server.recv(1024)

        print( bytes.decode(data) )



#New client.
main = Client()
print("Errors:", main.error)



#Start a thread with the recvMSG method.
thread = threading.Thread(target = main.recvMSG)
thread.start()

#Start the gui.
main.startGUI()

#Close the connection when the program terminates and stop threads.
main.running = False
main.server.close()
</code></pre>

<p>The program works fine exactly as i wanted.</p>

<p>But i have some more questions.</p>

<p><strong>r, w, x = select.select(self.sockets, [], self.sockets)</strong></p>

<p><strong>r</strong> is a list which contains all the ready sockets.
But i did not undesrand what <strong>w</strong> and <strong>x</strong> are.</p>

<p>The <strong>first</strong> parameter is the sockets list, the <strong>second</strong> the accepted clients
and the <strong>third</strong> parameter what is it? Why am i giving again the sockets list?</p>

python multithreading sockets