'Python - Unidirectional websocket

I'm trying to create a unidirectional websocket connection between the client and server (python). The libraries I've currently been prototyping with are websockets and simplesocketserver. I've got a hello world example getting from the server to the client, but I need to be able to send data from the backend to the client unprompted from the client. All of the websockets examples seem to show the server listening to the client and then responding.

So far I've tried:

  • Using websockets 8.0, sending data from server to client unprompted, this works but only with hard-coded strings, I don't understand how to send real data on demand unprompted from the client

  • Using simplesocketserver in the same exact manner

  • Started investigating server sent events - is this more appropriate?

Example from the websockets documentation:


import asyncio
import websockets

async def hello(websocket, path):
    name = await websocket.recv()
    print(f"< {name}")

    greeting = f"Hello {name}!"

    await websocket.send(greeting)
    print(f"> {greeting}")

start_server = websockets.serve(hello, "localhost", 8765)

asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()

Note: the need for unidirectional communication is due to existing architecture.

Any guidance or resources on this would be great, I hope I'm overlooking something easy. Thank you!



Solution 1:[1]

I came across a similar issue. After some trial and error I found a solution that works for me, maybe so it does for you. I've tested this on Linux and with Firefox and mobile Safari (parallel).

The InputThread waits for input (words) on the command line and writes them into a list, that is sent to all connected clients each time a new string is appended or a client is connected.


Code snippet
import asyncio
import websockets
import json
from threading import Thread


words = []
clients = []


async def register_client(websocket, path):
    # register new client in list and keep connection open
    clients.append(websocket)
    await send_to_all_clients()
    while True:
        await asyncio.sleep(10)


async def send_to_all_clients():
    global words
    for i, ws in list(enumerate(clients))[::-1]:
        try:
            await ws.send(json.dumps({"words": words}))
        except websockets.exceptions.ConnectionClosedError:
            # remove if connection closed
            del clients[i]


class InputThread(Thread):
    def run(self):
        global words

        async def sending_loop():
            while True:
                i = input()
                if not i.strip():
                    continue
                words.append({"options": i.strip().slit()})
                await send_to_all_clients()
        asyncio.run(sending_loop())


InputThread().start()
asyncio.get_event_loop().run_until_complete(
    websockets.serve(register_client, "localhost", 8765))
asyncio.get_event_loop().run_forever()

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1