简体   繁体   中英

Websockets Server Push in Python

How do I write a websockets server in Python which just pushes out data on a timed interval to all connected clients without waiting for any incoming messages?

I'm answering my own question...

This is a working example of a Python websockets server which sends out a message to all clients every 5 seconds. I wrote this and managed to get it working as I could not find a single example of this on the web (March 2021)

Hope this helps others, and if anyone has suggestions for improvements or better solutions using packages to maybe add ssl support or subscription type services additions, please write in the comments or answers section.

import asyncio
import logging
import websockets
from websockets import WebSocketServerProtocol
import time
import threading

logging.basicConfig(level=logging.INFO)


class Server:

    clients = set()
    logging.info(f'starting up ...')

    def __init__(self):
        logging.info(f'init happened ...')
        
    async def register(self, ws: WebSocketServerProtocol) -> None:
        self.clients.add(ws)
        logging.info(f'{ws.remote_address} connects')

    async def unregister(self, ws: WebSocketServerProtocol) -> None:
        self.clients.remove(ws)
        logging.info(f'{ws.remote_address} disconnects')

    async def send_to_clients(self, message: str) -> None:
        if self.clients:
            logging.info("trying to send")
            await asyncio.wait([client.send(message) for client in self.clients])

    async def ws_handler(self, ws: WebSocketServerProtocol, url: str) -> None:
        await self.register(ws)
        try:
            await self.distribute(ws)
        finally:
            await self.unregister(ws)

    async def distribute(self, ws: WebSocketServerProtocol) -> None:
        async for message in ws:
            await self.send_to_clients(message)


async def timerThread(server,counter):
    counter = 0
    while True:
        await checkAndSend(server,counter)
        print("doing " + str(counter))
        time.sleep(5)
        counter = counter + 1

async def checkAndSend(server,counter):
    # check something
    # send message
    logging.info("in check and send")
    await server.send_to_clients("Hi there: " + str(counter))

# helper routine to allow thread to call async function
def between_callback(server,counter):
    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)
    loop.run_until_complete(timerThread(server,counter))
    loop.close()

# start server
server = Server()
start_server = websockets.serve(server.ws_handler,'localhost',4000)
counter = 0 

# start timer thread
threading.Thread(target=between_callback,args=(server,counter,)).start()

# start main event loop
loop = asyncio.get_event_loop()
loop.run_until_complete(start_server)
loop.run_forever()

To see this working, you can use this simple html file as the client and then open the inspector to see the incoming messages on the Console log.

<h1> Websocket Test </h1>
<script>
const ws = new WebSocket('ws://localhost:4000')
ws.onopen = () => {
  console.log('ws opened on browser')
  ws.send('hello world')
}
ws.onmessage = (message) => {
  console.log(`message received`, message.data)
}
</script>
    from datetime import time
    import schedule
    import time
    import socket
    import threading

alarm_time = input()
my_string = str(alarm_time)
my_new_time = my_string.format("%H:%M %Z")

EADER = 64
PORT = xxxx
SERVER = 'xxxxxxxx'
ADDR = (SERVER, PORT)
FORMAT = 'utf-8'


server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(ADDR)


if alarm_time is not None and alarm_time != 0:
    print(f"Scheduled for: {my_new_time}")
else:
    sys.exit()
    
    def job():
            client.connect(ADDR)
            name_time = self.name_send + ' ' + my_date
            message = name_time.encode(FORMAT)
            msg_length = len(message)
            send_length = str(msg_length).encode(FORMAT)
            send_length += b' ' * (HEADER - len(send_length))
            client.send(send_length)
            client.send(message)
    
    
    schedule.every().day.at(my_new_time).do(job)
    
    
    while True:
        schedule.run_pending()
        time.sleep(1)

Not sure if this is any help tbh. But its a small tweak of a script I use with socket, subprocess etc to schedule them

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM