TCP server talking to multiple clients

I have found several echo server and chat-room server examples in python. I have tried some and they are working fine.

In echo server example, the echo server is listening the client all the time. The client can send a string message to the echo server and the echo server return the same string message to the client.

In chat-room server example, multiple clients can connect to the chat-room server. The chat-room server is listening to all the connected clients. The client can send a string message to the chat-room server and the chat-room server broadcast the string message to all the other clients.

I am actually looking a python example in which server decide what to send to the client and when to send. The server contains a list of all the connected clients. The server should have the status of all the clients. The server should be able to send a string message to one client at a time, not broadcast to all the clients and get a reply from the same client. This way the server is a kind of master and initiate the two-way communication with one client at a time. Each time the server will be sending a string message to a particular client and expect the reply from the same client.

Is there any python example program which I can run as a starting point ?

You’ve described a very standard pattern here, I think you’re on the right track. I don’t have example code for you; but if you take this paragraph you just wrote and convert it, step by step, into Python code, you should do well. Here’s where I would start:

  1. Grab one of your existing single-client-at-a-time echo systems
  2. Make the server operate asynchronously (using the asyncio module, or with threads; I would recommend asyncio)
  3. Maintain a collection of clients - a list, or a dict mapping some ID to their info, or similar.
  4. Have a function that attempts to send to all connected clients, and purges any that are no longer responsive

Your code will end up looking something like this:

import asyncio

async def handle_client(sock):
    try:
        while True:
            msg = await sock.recv()
    finally:
        sock.close()

async def listen_for_connections():
    mainsock = socket.socket(AF_INET, SOCK_STREAM)
    mainsock.bind(...)
    mainsock.listen()
    try:
        while True:
            sock, addr = await mainsock.accept()
            spawn_task(handle_client(sock))
    finally:
        mainsock.close()

asyncio.run_until_complete(listen_for_connections())

This is stubbed out and incomplete, and is meant more as a guide than a runnable example. But broadly speaking, this is the sort of architecture that I’d go with.

You should be able to find plenty of examples on the internet of how to use sockets with asyncio. They should be good pieces to build with.

Thank you very much for your quick reply. I understand you mention to use asyncio module.

In server program there has to be a input function which require input from server user. The user will enter the string message and the address of the destination client.

Kindly point me to an example which I can run directly and then I will modify the program accordingly.

Thanks in advance.

Ah, that’s an unusual feature for a server. But fortunately, asyncio can handle that too. You won’t be using the input() function, but the underlying sys.stdin stream can be used asynchronously, so you should be able to add an additional task (written as an async function) to handle that input.

I guess before I add multiple clients in the network. I first need to implement “echo client” in which one client connected to the server will be listening all the time to server and will reply the same back to the server. I think this can be done by reversing the echo server example program. I appreciate if someone can please identify the changes I need in the example.

# Server.py
print("This is TCP/IP Echo Server")
import socket

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = socket.gethostname()
port = 1255
s.bind((host, port))

s.listen(5)
socketclient, address = s.accept()

print("Got connected form", address)
print("\nListening to TCP/IP Client ... \n")

token = True
while token:
    msg = socketclient.recv(1024)
    msg = msg.decode("utf-8")
    print("TCP/IP Client:", msg)
    if msg == "quit":
        token = False
        s.close()
# Client.py
print("This is TCP/IP Echo Client")

import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = socket.gethostname()
port = 1255

s.connect((host, port))

token = True
while token:
    msg = input("Enter message send to TCP/IP Server: ")
    s.send(msg.encode("utf-8"))
    if msg == "quit":
        token = False
        s.close()

I would like to add something more in the description of my application.

We will have multiple Microcontroller boards as TCP clients. The TCP server will be on computer side. The TCP server will initiate the communication to the attached Microcontroller boards, talking to one at a time. The initial task is just to control the LEDs and read the status of DIP switches on Microcontroller boards.

I guess the Echo server and chat-room servers are something different, in which each client has to start sending a string message to the server and then the server either return the string message to the same client or broadcast to all the clients.

I think I need to look at Web server.

“A web server is software and hardware that uses HTTP (Hypertext Transfer Protocol) and other protocols to respond to client requests made over the World Wide Web.”

“Such a web server can be used to control or monitor an embedded platform through a browser.”

But then it is not Python, right ?

You can absolutely do that in Python! Python is quite good at building HTTP servers.

Thanks for your reply that HTTP servers also possible to build in Python.

I read that web or HTTP servers are infect request-response protocols, meaning a client initiates requests and a server listens to the requests and provides a response to the client, right ?

I am bit confused now. If we have multiple Microcontroller boards, can we use “one” web-server to communicate to all of them ? If yes, then all the Microcontroller boards will have to be ‘clients’, right ?

I am also wondering then how an embedded based monitoring system is working. If we need to monitor the system status from multiple Microcontroller boards. Each time, the Microcontroller ‘client’ boards need to start communication and tell the web server what is the status of the connected hardware ? Shouldn’t be the other way around ?

Yes, and yes. The normal way you would do this would be exactly what you described: a server on the computer and a client on each microcontroller.

It doesn’t have to be. The clients can push their status, and the server can report what it hears. If the server hasn’t heard status from one of them in a while, it can assume that that one is no longer operating.

You can also invert this, though. You can have a server on every microcontroller and a single client on the computer that connects to each one. That way, the microcontrollers need to report whenever they’re asked for it, and the client is the one that decides what to do when.

1 Like

One Python based single client on computer and multiple Microcontroller server boards possible ?

I didn’t know this before that one client can connect to multiple servers.

Yep! Each microcontroller will have its own IP address, and you can run a server on each one. Then the client connects to them all - one by one, or all at once - and gets responses.

Now I understand. Thanks for your reply.

This way it be a request based response from each Microcontroller server board and the client will be on Python HTTP based, correct ?

How about if there are around 45 to 50 Microcontroller boards. Would that be a problem with one client in Python ?

Can you please direct me to the reference design of Python based web server/client HTTP example ?

Hello again, I am still there with my question.

"I am actually looking a python example in which server decide what to send to the client and when to send. The server contains a list of all the connected clients. The server should have the status of all the clients. The server should be able to send a string message to one client at a time, not broadcast to all the clients and get a reply from the same client. This way the server is a kind of master and initiate the two-way communication with one client at a time. Each time the server will be sending a string message to a particular client and expect the reply from the same client.

Is there any python example program which I can run as a starting point ?"

Everything you’ve described is absolutely possible. You’ll need to write the code to do it, though. There are examples in the documentation, and you can put things together from there.

Kindly refer me to documentation with an example program that I can run. Thanks in advance.

Hello,

This is my Echo server program.

# Echo Server

print("This is TCP/IP Echo Server")
import socket

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = socket.gethostname()
port = 1255
s.bind((host, port))

s.listen(5)
socketclient, address = s.accept()

print("Got connected form", address)
print("\nListening to TCP/IP Client ... \n")

token = True
while token:
    msg = socketclient.recv(1024)
    msg = msg.decode("utf-8")
    print("TCP/IP Client:", msg)
    if msg == "quit":
        token = False
        s.close()

This is client program.

# Echo Client

print("This is TCP/IP Echo Client")

import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = socket.gethostname()
port = 1255

s.connect((host, port))

token = True
while token:
    msg = input("Enter message send to TCP/IP Server: ")
    s.send(msg.encode("utf-8"))
    if msg == "quit":
        token = False
        s.close()

I tried to swap the while loop from while token: to end. And replace msg = socketclient.recv(1024) with msg = s.recv(1024) in server program but this does not work.

Don’t know what do I need to change so that once the client is connected to the server, the server send hello message first and then client reply to the server message.

There is some progress. I manage to send messages from server to one client. I will put in another post.