|
| 1 | +#!/usr/bin/env python3 |
| 2 | +""" |
| 3 | +WebSocket 服务器 - 向 SelfAgent App 推送消息 |
| 4 | +部署到服务器后运行: python ws_server.py |
| 5 | +App 会自动连接 ws://111.170.6.103:9999/ws |
| 6 | +""" |
| 7 | + |
| 8 | +import asyncio |
| 9 | +import websockets |
| 10 | +import json |
| 11 | +from datetime import datetime |
| 12 | + |
| 13 | +# 存储所有连接的客户端 |
| 14 | +clients = set() |
| 15 | + |
| 16 | +async def handler(websocket, path): |
| 17 | + """处理客户端连接""" |
| 18 | + clients.add(websocket) |
| 19 | + client_ip = websocket.remote_address[0] |
| 20 | + print(f"[{datetime.now().strftime('%H:%M:%S')}] 新连接: {client_ip} (在线: {len(clients)})") |
| 21 | + |
| 22 | + try: |
| 23 | + async for message in websocket: |
| 24 | + print(f"[{datetime.now().strftime('%H:%M:%S')}] 收到: {message}") |
| 25 | + except websockets.exceptions.ConnectionClosed: |
| 26 | + pass |
| 27 | + finally: |
| 28 | + clients.discard(websocket) |
| 29 | + print(f"[{datetime.now().strftime('%H:%M:%S')}] 断开: {client_ip} (在线: {len(clients)})") |
| 30 | + |
| 31 | +async def broadcast(message): |
| 32 | + """向所有客户端广播消息""" |
| 33 | + if clients: |
| 34 | + msg = json.dumps({"title": "服务器通知", "body": message, "time": datetime.now().strftime('%H:%M:%S')}) |
| 35 | + await asyncio.gather(*[client.send(msg) for client in clients]) |
| 36 | + print(f"[{datetime.now().strftime('%H:%M:%S')}] 已推送给 {len(clients)} 个客户端") |
| 37 | + |
| 38 | +async def input_loop(): |
| 39 | + """命令行输入,输入消息后推送给所有客户端""" |
| 40 | + print("\n" + "="*50) |
| 41 | + print("WebSocket 服务器已启动 - ws://0.0.0.0:9999/ws") |
| 42 | + print("输入消息后回车即可推送到所有 App") |
| 43 | + print("="*50 + "\n") |
| 44 | + |
| 45 | + loop = asyncio.get_event_loop() |
| 46 | + while True: |
| 47 | + message = await loop.run_in_executor(None, input, "推送消息> ") |
| 48 | + if message.strip(): |
| 49 | + await broadcast(message.strip()) |
| 50 | + |
| 51 | +async def main(): |
| 52 | + server = await websockets.serve(handler, "0.0.0.0", 9999, path="/ws") |
| 53 | + await asyncio.gather(server.wait_closed(), input_loop()) |
| 54 | + |
| 55 | +if __name__ == "__main__": |
| 56 | + asyncio.run(main()) |
0 commit comments