简体   繁体   English

将 websocket 客户端消息路由到 websocket 服务器

[英]Route websocket client messages to websocket server

I'm trying to ingest data from an external WebSocket using Websocket Client A and send those messages to WebSocket Server B for clients connected to B to view.我正在尝试使用 Websocket 客户端 A 从外部 WebSocket 摄取数据,并将这些消息发送到 WebSocket 服务器 B 以供连接到 B 的客户端查看。 (Reason being, I'm trying to connect multiple external WebSockets and feed their messages to a single point, if this is a bad design can someone suggest an alternative) (原因是,我正在尝试连接多个外部 WebSocket 并将它们的消息提供给一个点,如果这是一个糟糕的设计,有人可以提出替代方案)

Running server B uvicorn server:app --reload then visit http://127.0.0.1:8000/运行服务器B uvicorn server:app --reload然后访问http://127.0.0.1:8000/

WebSocket Server B WebSocket 服务器 B

from typing import List

from fastapi import FastAPI, WebSocket, WebSocketDisconnect
from fastapi.responses import HTMLResponse

app = FastAPI()

html = """
<!DOCTYPE html>
<html>
    <head>
        <title>Screener</title>
    </head>
    <body>
        <h2>Your ID: <span id="ws-id"></span></h2>
        <ul id='messages'>
        </ul>
        <script>
            var client_id = Date.now()
            document.querySelector("#ws-id").textContent = client_id;
            var ws = new WebSocket(`ws://localhost:8000/ws/${client_id}`);
            ws.onmessage = function(event) {
                var messages = document.getElementById('messages')
                var message = document.createElement('li')
                var content = document.createTextNode(event.data)
                message.appendChild(content)
                messages.appendChild(message)
            };
            function sendMessage(event) {
                var input = document.getElementById("messageText")
                ws.send(input.value)
                input.value = ''
                event.preventDefault()
            }
        </script>
    </body>
</html>
"""


class ConnectionManager:
    def __init__(self):
        self.active_connections: List[WebSocket] = []

    async def connect(self, websocket: WebSocket):
        await websocket.accept()
        self.active_connections.append(websocket)

    def disconnect(self, websocket: WebSocket):
        self.active_connections.remove(websocket)

    async def send_personal_message(self, message: str, websocket: WebSocket):
        await websocket.send_text(message)

    async def broadcast(self, message: str):
        for connection in self.active_connections:
            await connection.send_text(message)


manager = ConnectionManager()


@app.get("/")
async def get():
    return HTMLResponse(html)


@app.websocket("/ws/{client_id}")
async def websocket_endpoint(websocket: WebSocket, client_id: int):
    await manager.connect(websocket)
    try:
        while True:
            data = await websocket.receive_text()
            await manager.send_personal_message(f"You wrote: {data}", websocket)
            await manager.broadcast(f"Client #{client_id} says: {data}")
    except WebSocketDisconnect:
        manager.disconnect(websocket)
        await manager.broadcast(f"Client #{client_id} left the chat")

WebSocket ClientA WebSocket 客户端A

#!/usr/bin/env python
import websocket
import _thread
import time
import asyncio
import websockets

from concurrent.futures import ThreadPoolExecutor

_EXECUTOR_ = ThreadPoolExecutor(1)

async def main_loop():
  async with websockets.connect("ws://localhost:8000/ws/1") as server_ws:
    await server_ws.send("main_loop")
    
    def send_message(message):
      server_ws.send(message)

    def ws_message(ws, message):
      loop = asyncio.get_event_loop()
      loop.run_in_executor(_EXECUTOR_, send_message, message)
      print("WebSocket thread: %s" % message)

    def ws_open(ws):
      ws.send('{"event":"subscribe", "subscription":{"name":"trade"}, "pair":["XBT/USD","XRP/USD"]}')

    def ws_thread(*args):
      ws = websocket.WebSocketApp("wss://ws.kraken.com/", on_open = ws_open, on_message = ws_message)
      ws.run_forever()

    _thread.start_new_thread(ws_thread, ())

    while True:
        time.sleep(5)
        print("Main thread: %d" % time.time())

asyncio.run(main_loop())

What is the question?问题是什么?

WS is kind of a multiplex connection that allows each side (server/client or whatever) to both send and receive messages in an asynchronous way. WS 是一种多路连接,允许每一方(服务器/客户端或其他)以异步方式发送和接收消息。 Ingesting data from one side of the WS (in your case Client A) and consuming some related data through another API is OK - it all depends on your needs.从 WS 的一侧(在您的情况下为客户端 A)摄取数据并通过另一个 API 使用一些相关数据是可以的 - 这完全取决于您的需求。

This approach kind of reminds me of a classic Pub/Sub pattern.这种方法让我想起了经典的 Pub/Sub 模式。 Where you have an API that you ingest data through and pass it to a Queue (RabbitMQ, Google Pub/Sub service/AWS SNS) the messages ingested into the queue are being consumed by another service that parses the data and populates some DB, Then any other client can access a third service (API) to consume the relevant data.如果您有一个 API,您可以通过该 API 摄取数据并将其传递给队列(RabbitMQ、Google Pub/Sub 服务/AWS SNS),摄取到队列中的消息正在被另一个解析数据并填充一些数据库的服务使用,然后任何其他客户端都可以访问第三方服务 (API) 以使用相关数据。

Nice explanation about the Pub/Sub pattern Link1 , Link2 Not sure what advantage WebSockets provide in your example关于 Pub/Sub 模式的很好解释Link1Link2不确定 WebSockets 在您的示例中提供了什么优势

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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