【问题标题】:Python Send Data to WebsocketsPython 向 Websocket 发送数据
【发布时间】:2019-12-17 05:52:52
【问题描述】:

我正在尝试使用超级简单的 websocket 将我的全局鼠标光标位置流式传输到 web 客户端。

这两件事我都发生了,我的客户端(在 JS 中)工作正常,但我不知道如何连接它们;我想在调用 move() 时发送一条 websocket 消息,但是我尝试过的所有操作都会引发错误。

此代码打印出鼠标位置并运行 websocket,但我怎样才能让两者相互“交谈”?

import asyncio
import websockets
from pynput import mouse

def onmove(x, y):
    print(x,y)

async def socket_handler(websocket, path):
    while True:
        message = await websocket.recv()
        print(f"Received {message}")

        resp = f'WS Message Was: {message}'
        await websocket.send(resp)


listener = mouse.Listener(on_move = onmove)
listener.start()

start_server = websockets.serve(socket_handler, "127.0.0.1", 5000)
asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()

我觉得肯定有一个非常明显的答案,我只是不太了解异步和事件循环

【问题讨论】:

    标签: python python-3.x websocket python-asyncio


    【解决方案1】:

    你的 pynput 和 asyncio 东西有多个线程。要跨线程共享数据,您需要一个线程安全的容器。一种选择是 python 的 queue 模块。

    一个更好的选择——从 asyncio 的角度来看——正如 user4815162342 在 cmets 中指出的那样,是使用 asyncio 的 Queue 和来自其他线程的 asyncio 的 event_loop 上的 call_soon_threadsafe。这是一个例子:

    import asyncio
    import json
    import websockets
    from pynput import mouse
    
    q = asyncio.Queue()
    
    def onmove(x, y):
        loop.call_soon_threadsafe(q.put_nowait, (x,y))
    
    async def socket_handler(websocket, path):
        while True:
            message = await q.get()
            await websocket.send(json.dumps(message))
    
    loop = asyncio.get_event_loop()
    start_server = websockets.serve(socket_handler, "127.0.0.1", 5000)
    loop.run_until_complete(start_server)
    
    listener = mouse.Listener(on_move = onmove)
    listener.start()
    loop.run_forever()
    

    使用标准 queue.Queue 的旧示例。

    example_server.py

    import asyncio
    import queue
    import json
    import websockets
    from pynput import mouse
    
    q = queue.SimpleQueue()
    
    def onmove(x, y):
        try:
            print("Putting: {0}".format((x,y)))
            q.put((x,y), block=False)
        except q.Full:
            print("Dropped coords: {0}".format((x,y)))
    
    async def getCoords():
        coords = None
        try:
            coords = q.get(block=False)
        except queue.Empty:
            # print("QUEUE EMPTY")
            pass
        return coords
    
    async def socket_handler(websocket, path):
        while True:
            message = await getCoords()
            if message:
                await websocket.send(json.dumps(message))
    
    listener = mouse.Listener(on_move = onmove)
    listener.start()
    
    loop = asyncio.get_event_loop()
    start_server = websockets.serve(socket_handler, "127.0.0.1", 5000)
    loop.run_until_complete(start_server)
    loop.run_forever()
    

    example_client.html

    <html>
    <head>
    <script
      src="https://code.jquery.com/jquery-3.4.1.min.js"
      integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo="
      crossorigin="anonymous"></script>
    <script>
    $(function() {
       var exampleSocket = new WebSocket("ws://127.0.0.1:5000");
       exampleSocket.onmessage = function (event) {
             var coords = JSON.parse(event.data);
             $('#x').html(coords[0]);
             $('#y').html(coords[1]);
       };
    });
    </script>
    </head>
    <body>
    <p>X: <span id="x"></span></p>
    <p>Y: <span id="y"></span></p>
    </body>
    </html>
    

    【讨论】:

    • 谢谢你,这正是我所需要的,我已经在一个线程中构建了一个不同的版本,而且效率非常低......我已经添加了队列清除和睡眠计时器while 循环,它使用的资源比我的单线程循环少得多。
    • 这种方法的问题是如果鼠标不动,socket_handler 会忙循环。您可以改用asyncio.Queue 来改进它。那么getCoord() 可以只是await q.get(),而onmove 可以通过使用event_loop.call_soon_threadsafe(q.put_nowait, (x, y)) 实现线程安全。
    猜你喜欢
    • 2021-06-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多