5

I have a code which works perfectly for one connection. I have seen two options for multi-client handling but I don't really understand it. Here is the server socket code:

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as listening_sock:
    listening_sock.bind(('', port))
    listening_sock.listen()
    client_soc, client_address = listening_sock.accept()
    client_soc.sendall('200#Welcome to my server!'.encode())
    print(f'Address {client_soc.getsockname()[0]} connected with port {client_soc.getsockname()[1]}')
    while True:
        # get message
        msg = client_soc.recv(1024).decode()
        # receive log print:
        print(f'"{msg}" sent from {client_soc.getsockname()[0]}')
        if 'Quit' in msg:
            client_soc.sendall('200#Thanks for using my server!'.encode())
            client_soc.close()
        elif '0' < msg.split('#')[0] <= '9':  # one of the valid actions
            answer = call_action(msg.split('#')[0], db, msg.split('#')[1])  # the answer for given parameter
            client_soc.sendall("200#".encode() + answer.encode())

If I have only one connection it works good and last thing I need to add is option for multiple-client handling. What is the shortest and easiest way to do it?

2 Answers 2

6

The code only calls accept once. Instead, call accept in a while loop and create a thread for each client connection so they are handled in parallel. Use the following pattern as an example:

import socket
import threading

# Thread to handle each "client_soc" connection
def handler(client_soc):
    with client_soc:  # closes socket when with block exits
        ...

with socket.socket() as listening_sock:
    listening_sock.bind(('', 8000))
    listening_sock.listen()
    while True:
        client_soc, client_address = listening_sock.accept()
        # Send each "client_soc" connection as a parameter to a thread.
        threading.Thread(target=handler, args=(client_soc,), daemon=True).start() 

There is also a built-in socket server that simplifies this process. Here's a tested example echo server that echoes back newline-terminated data:

from socketserver import ThreadingTCPServer, StreamRequestHandler

class echohandler(StreamRequestHandler):
    def handle(self):
        print(f'Connected: {self.client_address[0]}:{self.client_address[1]}')
        while True:
            # rfile and wfile are created with socket.makefile()
            # and wrap the socket in file-like objects for reading and
            # writing the socket.
            #
            # Get newline-terminated message.
            msg = self.rfile.readline()
            if not msg:
                print(f'Disconnected: {self.client_address[0]}:{self.client_address[1]}')
                break # exits handler, framework closes socket
            print(f'Received: {msg}')
            self.wfile.write(msg)
            self.wfile.flush()  # file-like object must be flushed to ensure send.

server = ThreadingTCPServer(('', 8000), echohandler)
server.serve_forever()
Sign up to request clarification or add additional context in comments.

Comments

2

Your code blocks itself.

For instance: client_soc, client_address = listening_sock.accept() Accepts client, then while True: runs forever, so you can work with 1 connection only, because socket.accept() is called once. You should learn some of these to solve your problem: asyncio, threading, multiprocessing. These libraries will help your code to accept and work with clients concurrently. Sockets can use every, but often they are paired with asyncio: https://asyncio.readthedocs.io/

2 Comments

Should I make a function that works with a single socket and use it multiple times or something similiar?
Yes, you can do something like this def handle_client(): your code for client # after accept import threading threading.Thread(target=handle_client, args=(client_soc,)).start() That will run new thread, but there are so many things to learn, and you should watch videos on youtube on these topics or read documentation.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.