首页 > 解决方案 > 如何在运行 while-True 循环时向任何连接的客户端发送 websocket 更新?

问题描述

我有一个 Python3 程序,它运行“ while True ”循环直到停止,它偶尔会将数据保存到 MySQL 数据库中。我正在创建一个与 Python 程序分开的管理网站,我将能够在其中观察这些数据。

我现在希望能够在对数据库进行更改时在网站上收到通知。我的想法是建立一个 websocket 连接,以便 Python 程序可以通过套接字向所有连接的客户端发送消息,即所有打开的浏览器,如果数据库表有任何更改。

我以前做过类似的事情,但在那种情况下,我必须在“ while True ”循环开始之前等待 websocket 连接。在新场景中,我希望能够同时拥有多个网站客户端,并让它们随时连接,以及在不中断 Python 程序循环的情况下断开连接。

这是我之前代码的简化版本,我现在想更新它以便能够在有和没有 websocket 客户端的情况下运行。

import asyncio
import websockets

socket_server = websockets.serve(run, "127.0.0.1", 5055)
asyncio.get_event_loop().run_until_complete(socket_server)
console_log("Waiting for socket connection...")
asyncio.get_event_loop().run_forever()

async def run(ws):
    while True:
        db_has_updated = do_stuff()
        if db_has_updated:
            await ws.send(data)

我似乎无法想出正确的搜索词来找到解决方案,所以我在这里问。

标签: pythonpython-3.xwebsocket

解决方案


我终于想通了!这是我的解决方案,其中一个 websocket 服务器在与其他逻辑不同的线程中运行。我可能正在更改一些东西以使其更整洁,但这可以满足我的一切需求。随意问任何问题。

请注意,在向所有连接的客户端发送消息时,这会阻塞。这就是我需要它工作的方式,但如果你希望它完全异步运行,你总是可以线程/子处理程序的逻辑/数据生成部分。

#!/usr/bin/env python3

import asyncio
import websockets
import threading
import time
import random

def gen_data():
    print("Generating data...")
    time.sleep(3)
    data = random.randint(1, 10)
    
    return data

async def send(client, data):
    await client.send(data)

async def handler(client, path):
    # Register.
    print("Websocket Client Connected.", client)
    clients.append(client)
    while True:
        try:
            print("ping", client)
            pong_waiter = await client.ping()
            await pong_waiter
            print("pong", client)
            time.sleep(3)
        except Exception as e:
            clients.remove(client)
            print("Websocket Client Disconnected", client)
            break

clients = []
start_server = websockets.serve(handler, "localhost", 5555)

asyncio.get_event_loop().run_until_complete(start_server)
threading.Thread(target = asyncio.get_event_loop().run_forever).start()

print("Socket Server Running. Starting main loop.")

while True:
    data = str(gen_data())
    message_clients = clients.copy()
    for client in message_clients:
        print("Sending", data, "to", client)
        try:
            asyncio.run(send(client, data))
        except:
            # Clients might have disconnected during the messaging process,
            # just ignore that, they will have been removed already.
            pass

推荐阅读