Python Socket Multiple Clients

175,599

Solution 1

Based on your question:

My question is, using the code below, how would you be able to have multiple clients connected? I've tried lists, but I just can't figure out the format for that. How can this be accomplished where multiple clients are connected at once and I am able to send a message to a specific client?

Using the code you gave, you can do this:

#!/usr/bin/python           # This is server.py file                                                                                                                                                                           

import socket               # Import socket module
import thread

def on_new_client(clientsocket,addr):
    while True:
        msg = clientsocket.recv(1024)
        #do some checks and if msg == someWeirdSignal: break:
        print addr, ' >> ', msg
        msg = raw_input('SERVER >> ')
        #Maybe some code to compute the last digit of PI, play game or anything else can go here and when you are done.
        clientsocket.send(msg)
    clientsocket.close()

s = socket.socket()         # Create a socket object
host = socket.gethostname() # Get local machine name
port = 50000                # Reserve a port for your service.

print 'Server started!'
print 'Waiting for clients...'

s.bind((host, port))        # Bind to the port
s.listen(5)                 # Now wait for client connection.

print 'Got connection from', addr
while True:
   c, addr = s.accept()     # Establish connection with client.
   thread.start_new_thread(on_new_client,(c,addr))
   #Note it's (addr,) not (addr) because second parameter is a tuple
   #Edit: (c,addr)
   #that's how you pass arguments to functions when creating new threads using thread module.
s.close()

As Eli Bendersky mentioned, you can use processes instead of threads, you can also check python threading module or other async sockets framework. Note: checks are left for you to implement how you want and this is just a basic framework.

Solution 2

accept can continuously provide new client connections. However, note that it, and other socket calls are usually blocking. Therefore you have a few options at this point:

  • Open new threads to handle clients, while the main thread goes back to accepting new clients
  • As above but with processes, instead of threads
  • Use asynchronous socket frameworks like Twisted, or a plethora of others

Solution 3

Here is the example from the SocketServer documentation which would make an excellent starting point

import SocketServer

class MyTCPHandler(SocketServer.BaseRequestHandler):
    """
    The RequestHandler class for our server.

    It is instantiated once per connection to the server, and must
    override the handle() method to implement communication to the
    client.
    """

    def handle(self):
        # self.request is the TCP socket connected to the client
        self.data = self.request.recv(1024).strip()
        print "{} wrote:".format(self.client_address[0])
        print self.data
        # just send back the same data, but upper-cased
        self.request.sendall(self.data.upper())

if __name__ == "__main__":
    HOST, PORT = "localhost", 9999

    # Create the server, binding to localhost on port 9999
    server = SocketServer.TCPServer((HOST, PORT), MyTCPHandler)

    # Activate the server; this will keep running until you
    # interrupt the program with Ctrl-C
    server.serve_forever()

Try it from a terminal like this

$ telnet localhost 9999
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Hello
HELLOConnection closed by foreign host.
$ telnet localhost 9999
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Sausage
SAUSAGEConnection closed by foreign host.

You'll probably need to use A Forking or Threading Mixin too

Solution 4

This program will open 26 sockets where you would be able to connect a lot of TCP clients to it.

#!usr/bin/python
from thread import *
import socket
import sys

def clientthread(conn):
    buffer=""
    while True:
        data = conn.recv(8192)
        buffer+=data
        print buffer
    #conn.sendall(reply)
    conn.close()

def main():
    try:
        host = '192.168.1.3'
        port = 6666
        tot_socket = 26
        list_sock = []
        for i in range(tot_socket):
            s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            s.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
            s.bind((host, port+i))
            s.listen(10)
            list_sock.append(s)
            print "[*] Server listening on %s %d" %(host, (port+i))

        while 1:
            for j in range(len(list_sock)):
                conn, addr = list_sock[j].accept()
                print '[*] Connected with ' + addr[0] + ':' + str(addr[1])
                start_new_thread(clientthread ,(conn,))
        s.close()

    except KeyboardInterrupt as msg:
        sys.exit(0)


if __name__ == "__main__":
    main()
Share:
175,599
Alec
Author by

Alec

Updated on August 18, 2021

Comments

  • Alec
    Alec over 2 years

    So I am working on an iPhone app that requires a socket to handle multiple clients for online gaming. I have tried Twisted, and with much effort, I have failed to get a bunch of info to be sent at once, which is why I am now going to attempt socket.

    My question is, using the code below, how would you be able to have multiple clients connected? I've tried lists, but I just can't figure out the format for that. How can this be accomplished where multiple clients are connected at once and I am able to send a message to a specific client?

    Thank you!

    #!/usr/bin/python           # This is server.py file
    
    import socket               # Import socket module
    s = socket.socket()         # Create a socket object
    host = socket.gethostname() # Get local machine name
    port = 50000                # Reserve a port for your service.
    
    print 'Server started!'
    print 'Waiting for clients...'
    
    s.bind((host, port))        # Bind to the port
    s.listen(5)                 # Now wait for client connection.
    c, addr = s.accept()     # Establish connection with client.
    print 'Got connection from', addr
    while True:
       msg = c.recv(1024)
       print addr, ' >> ', msg
       msg = raw_input('SERVER >> ')
       c.send(msg);
       #c.close()                # Close the connection
    
    • Mayli
      Mayli almost 12 years
      Make a while of c, addr = s.accept() when a client connected store them in a client_list, and then start a Thread of it.
    • Alec
      Alec almost 12 years
      Would it be like.... while: c, addr = s.accept() client_list = [] client_list.append(c, addr)
    • sarnold
      sarnold almost 12 years
      I know it's a huge change, but consider Ruby's EventMachine -- I found the EventMachine documentation significantly easier to read and understand than the Twisted documentation. The downside to Ruby is the smaller ecosystem of library bindings and packages, but it's better than it once was...
    • Alec
      Alec almost 12 years
      @sarnold I would rather stick with Python, I just feel it would be good to stick with it. Thanks for your suggestion though.
    • Mayli
      Mayli almost 12 years
      @AlecK. You need to have the client_list=[] out of the while loop, a good example is here, if you want just C-c C-v.
    • sarnold
      sarnold almost 12 years
      @AlecK., yeah, I can understand, especially if you've got other code written in Python. It just strikes me every time I see Twisted documentation how complicated they've made some things...
    • Alec
      Alec almost 12 years
      @Mayli I am not very experienced in this, so I can't quite figure it out. I'm not understanding it good enough.
    • Mayli
      Mayli almost 12 years
      @AlecK. Did you check the example link? Modify that example then run it, and you will get what you want. The Server class could handle multiple clients. If you want to learn more, read the code.
    • Alec
      Alec almost 12 years
      @Mayli So I can't just use lists? It has to be that in-depth? I know when I used Twisted it seemed simpler.
    • Mayli
      Mayli almost 12 years
      @AlecK. Twisted is a more complex twisted asynchronous lib than the example give. If you are making a really complex project, it's worth spending time learning it. When you using lists, it more like a synchronous way in which your code is blocked in every network communication.
    • Alec
      Alec almost 12 years
      @Mayli Can you give me a start in this while loop? I just can't think right now. :(
    • Daniel F
      Daniel F over 5 years
      A thread per client does not scale. I know Twisted is hard to get into, but once you have some experience with it, it is the goto-tool for almost all network related stuff. Stuff like the one you're trying to solve.
  • hoangpx
    hoangpx over 7 years
    Could you check this again. I got this error " data = clientsocket.recv(16384) AttributeError: 'tuple' object has no attribute 'recv'"
  • cascading-style
    cascading-style almost 7 years
    Is there a way to keep multiple connections alive using this?
  • ViFI
    ViFI almost 6 years
    Towards the 3rd point, Python now (3.5 onwards) has an in-built support of "asyncio" for asynchronous programming
  • nog642
    nog642 almost 5 years
    The clientsocket.close() after the while True: in the function and the s.close() after the while True: at the bottom will never be called, since there are no breaks in the while True: and the only way to exit the loop is with an exception, that will not be caught and will end the thread. A context manager would be a better way to make sure the socket is closed.
  • NaNdy
    NaNdy about 4 years
    I have adapted your program for python3 and it is coming up with this error Traceback (most recent call last): File "mydir\Server.py", line 29, in <module> print(f"Got connection from \"{addr}\"") NameError: name 'addr' is not defined
  • Vladimir Stazhilov
    Vladimir Stazhilov almost 4 years
    @cascading-style I don't think so, I tried that because I had multiple client connections, and it was randomely timing out
  • Jonathan
    Jonathan over 3 years
    Shouldn't import thread read from threading import Thread and thread.start_new_thread() then be replaced by Thread(target=on_new_client, args=(c,addr)) at least for Python 3?
  • Abdul Aziz Barkat
    Abdul Aziz Barkat about 3 years
    While this may answer the question, please consider adding an explanation.
  • Patrizio Bertoni
    Patrizio Bertoni over 2 years
    Yes there's a simple way, just instantiate a socketserver.ThreadingTCPServer instead of a socketserver.TCPServer (at least on a modern python interpreter such as 3.8.8)