How to use multithreading with websockets?

Viewed 2350

I am trying to use a websocket (https://websockets.readthedocs.io/en/stable/) using multithreading. What I want is to keep getting data while my program continues running, however, when I'm doing it like the code below, the server isn't receiving any connections from a client. I was running it before on the main thread and it was working well.

async def hello(websocket, path):
    while True:
        data = await websocket.recv()
        print(data)
        await websocket.send(data)


def between_callback():
    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)
    ws_server = websockets.serve(hello, '192.168.0.115', 8899)
    
    loop.run_until_complete(ws_server)
    loop.close()

if __name__ == "__main__":
    _thread = threading.Thread(target=between_callback)
    _thread.start()

  # Do something in main thread
1 Answers

Looking at the websockets sample programs, you seem to be missing one statement, loop.run_forever(), which did seem to make a difference (I also changed the IP address to 'localhost' for testing):


def between_callback():
    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)
    ws_server = websockets.serve(hello, 'localhost', 8899)

    loop.run_until_complete(ws_server)
    loop.run_forever() # this is missing
    loop.close()

DEMO Program

Note the updated hello function that avoids a websockets.exceptions.ConnectionClosedOK: code = 1000 (OK), no reason exception at termination, which arose, I suspect, due to the termination of the daemon thread.

import websockets
import threading
import asyncio

async def hello(websocket, path):
    async for data in websocket:
        print(f"Received: '{data}'")
        await websocket.send(data)

def between_callback():
    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)
    ws_server = websockets.serve(hello, 'localhost', 8899)

    loop.run_until_complete(ws_server)
    loop.run_forever() # this is missing
    loop.close()

async def send_receive_message(uri):
    async with websockets.connect(uri) as websocket:
        await websocket.send('This is some text.')
        reply = await websocket.recv()
        print(f"The reply is: '{reply}'")

def client():
    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)
    loop.run_until_complete(send_receive_message('ws://localhost:8899'))
    loop.close()

if __name__ == "__main__":
    # daemon server thread:
    server = threading.Thread(target=between_callback, daemon=True)
    server.start()
    client = threading.Thread(target=client)
    client.start()
    client.join()

Prints:

Received: 'This is some text.'
The reply is: 'This is some text.'
Related