Websocket Client only sends message once when `send` is being called several times

I’m making a library for adding multiplayer to python games. The library is an extra layer above the websockets library. I’m currently writing a test for it where two squares are controlled by two clients and move on both clients. Whenever the square is moved, I send an update to the server. The first time I do this, it works fine. However, any subsequent sends, and the message just seems to get lost. I get past the websocket.send call at the client but the message doesn’t arrive at the server.

Originally I thought the message wasn’t being handled correctly on the server’s side. However if I keep moving the square around, the websocket times out even though I should be sending loads of messages.

The code to receive the messages:

async for msg_json in websocket:
print("Message received")
msg = loads(msg_json)
self.msg_handler(msg, new_client.id)
print("Message handled")

The code to send the messages:

async def send_update():
msg = {"type": "update", "content": {"x": self.x, "y": self.y}, "id": self.id}
await client.send(dumps(msg))
print("Sent update")

Thanks in advance!

Make sure you are applying the required indentation in your code.

Does client.send flush the data to the network or is the data waiting in a buffer?

client.send() is the same as websocket.send() in the websockets library (see above). From what I have read, the clients have a write buffer that messages get put in until sent. I think I am able to change the limit on this buffer however I’m not 100% sure.

You are waiting for a message that will never arrive; you are not sending any message while handling the JSON message object.

As you can see, I print “Sent update” after sending the message so it isn’t getting stuck at that line. I also tried sending back a response after handling the message but that didn’t work either.

Could you please create a minimal, reproducible example using the ‘websockets’ library instead of using your own library?

How? Just show us how you are making use of the ‘websockets’ library.

If you want to see the code for the library and test, the library is here in TCPServer.py and client.py. The test is here.

I just finished an example that encounters the exact same problem. Here’s the code.

Server:

import websockets
import asyncio

clients = []


async def proxy(websocket):
    try:
        print("Connected")
        clients.append(websocket)
        async for message in websocket:
            print("Received message:", message)
            websockets.broadcast(clients, message)

    finally:
        clients.remove(websocket)


async def main():
    async with websockets.serve(proxy, "localhost", 8765):
        await asyncio.Future()


asyncio.run(main())

Client:

import websockets
import asyncio
import threading

msg_list = []


async def add_msgs_to_list(ws):
    async for msg in ws:
        msg_list.append(msg)


async def proxy(websocket):
    global msg_list
    while True:
        for msg in msg_list:
            msg_list.remove(msg)
            print("Received message:", msg)

        await websocket.send(input("Enter message: "))


async def main():
    async with websockets.connect("ws://localhost:8765") as websocket:
        t = threading.Thread(target=asyncio.run, args=(add_msgs_to_list(websocket),))
        t.start()
        await proxy(websocket)


asyncio.run(main())

You are mixing futures between different loops by using threading. In other words, you create two loops and then pass futures between them. It cannot work that way.

You may want to refer to the quick start guide to create your server-client example: Quick start - websockets 12.0 documentation

How would I handle incoming messages if I don’t know when they will arrive without blocking the program? I’ve tried using the normal async for msg in websocket but this doesn’t let any code run after this. When I need to draw the screen every frame and handle input etc., I can’t have the program blocked. Thanks!

Run the client in another thread; keep your game in the main thread.

import asyncio
import threading
import websockets
import time


async def websocket_handler():
    uri = "ws://localhost:8765"
    
    async with websockets.connect(uri) as websocket:
        while True:
            await websocket.send(input("Enter message: "))
            
            # Your WebSocket logic here
            message = await websocket.recv()
            print(f"Received message: {message}")


def start_websocket_thread():
    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)
    
    loop.run_until_complete(websocket_handler())


if __name__ == "__main__":
    # Create a new thread for the WebSocket client
    websocket_thread = threading.Thread(target=start_websocket_thread)
    
    # Start the WebSocket thread
    websocket_thread.start()
    
    try:
        # Your main application logic can run here
        while True:
            # Do other tasks in the main thread
            print('Ho ho ho')
            
            time.sleep(2.0)
    
    except KeyboardInterrupt:
        # Handle keyboard interrupt (Ctrl+C) to gracefully stop the WebSocket thread
        pass
    
    finally:
        # Stop the WebSocket thread when the main application exits
        websocket_thread.join()

1 Like

Thanks a lot!

Sorry this is late, but I can’t for the life of me figure out how I can interrupt the message loop the send a message. Doesn’t matter what I try, nothing worked. Thanks for the help.

Just break the loop.

I’m using a async for msg in ws and get this to send a message as soon as I need to. If I have a condition in the loop that checks if a message needs to be sent but this means the message will only be sent when a message is received.

I had similar problem. A websocket has buffer and if the send command does not fill the buffer, the data remains on a client side and not flushed. The solution was to set write_limit=0 (or to make it small).

https://websockets.readthedocs.io/en/stable/topics/memory.html#websockets-buffers