【问题标题】:Why can't I send down a websocket in a coroutine called by a coroutine?为什么我不能在协程调用的协程中发送 websocket?
【发布时间】:2017-08-10 15:59:39
【问题描述】:

为什么会这样:

async def setup():
    async with websockets.connect('ws:/ip.address:port') as ws:
        await ws.send('TEST MESSAGE')

def startup():
    loop = asyncio.new_event_loop() # because it's running in a thread
    asyncio.set_event_loop(loop)
    asyncio.ensure_future(setup())
    loop.run_forever()

通过 websocket 发送消息并:

async def setup():
    async with websockets.connect('ws:/ip.address:port') as ws:
        loop = asyncio.get_event_loop()
        loop.create_task(send_messages(ws))

async def send_messages(ws):
    await ws.send('TEST MESSAGE')

def startup():
    loop = asyncio.new_event_loop() # because it's running in a thread
    asyncio.set_event_loop(loop)
    asyncio.ensure_future(setup())
    loop.run_forever()

没有?

我已经从我的代码中删减了代码以简化它 - 如有必要,可以发布原始代码。第二个版本似乎挂在 await ws.send('test') 部分,因为打开了日志记录、调试等。

我想知道将 websocket 连接作为参数传递是否存在问题。如果您记录那里传递的内容和接收的内容,它们都会返回 <websockets.client.WebSocketClientProtocol object at 0x04B51A90> 并具有相同的地址。

我最终想要做什么,以及如何做到这一点的建议,即使问题无法回答,我们也欢迎:

运行两个协程,几乎永远运行: * 从 tkinter GUI 的常规函数​​放置的队列中获取消息,并将它们发送到 websocket * 从 websocket 获取消息并更改 GUI 中的内容

我认为 websockets 库作为 asyncio 将是执行此操作的方法,但我愿意接受任何建议。

编辑:忘记添加错误信息!

2017-03-19 10:49:31,103 ERROR asyncio Task exception was never retrieved
future: <Task finished coro=<send_messages() done, defined at chessboard.py:74> exception=ConnectionClosed('WebSocket connection is closed: code = 1000, no reason.',) created at chessboard.py:103>
source_traceback: Object created at (most recent call last):
  File "C:\Program Files (x86)\Python35-32\lib\threading.py", line 882, in _bootstrap
    self._bootstrap_inner()
  File "C:\Program Files (x86)\Python35-32\lib\threading.py", line 914, in _bootstrap_inner
    self.run()
  File "C:\Program Files (x86)\Python35-32\lib\threading.py", line 862, in run
    self._target(*self._args, **self._kwargs)
  File "chessboard.py", line 120, in startup
    loop.run_forever()
  File "C:\Program Files (x86)\Python35-32\lib\asyncio\base_events.py", line 345, in run_forever
    self._run_once()
  File "C:\Program Files (x86)\Python35-32\lib\asyncio\base_events.py", line 1312, in _run_once
    handle._run()
  File "C:\Program Files (x86)\Python35-32\lib\asyncio\events.py", line 125, in _run
    self._callback(*self._args)
  File "C:\Program Files (x86)\Python35-32\lib\asyncio\tasks.py", line 307, in _wakeup
    self._step()
  File "C:\Program Files (x86)\Python35-32\lib\asyncio\tasks.py", line 239, in _step
    result = coro.send(None)
  File "chessboard.py", line 103, in setup
    loop.create_task(send_messages(ws))
Traceback (most recent call last):
  File "C:\Program Files (x86)\Python35-32\lib\asyncio\tasks.py", line 239, in _step
    result = coro.send(None)
  File "C:\Program Files (x86)\Python35-32\lib\asyncio\coroutines.py", line 121, in send
    return self.gen.send(value)
  File "chessboard.py", line 81, in send_messages
    await ws.send(str(message))#seems to be stopping here - why isn't it sending?
  File "C:\Program Files (x86)\Python35-32\lib\site-packages\websockets\protocol.py", line 309, in send
    yield from self.ensure_open()
  File "C:\Program Files (x86)\Python35-32\lib\site-packages\websockets\protocol.py", line 401, in ensure_open
    raise ConnectionClosed(self.close_code, self.close_reason)
websockets.exceptions.ConnectionClosed: WebSocket connection is closed: code = 1000, no reason.

【问题讨论】:

    标签: python websocket python-asyncio


    【解决方案1】:

    可以将 websocket 作为参数传递。这里的问题是,当等待 send 协程时,websocket 连接已经关闭(如您的错误消息中所述)。这是因为连接上下文在send_messages 任务可以发送消息之前完成。

    请考虑以下工作示例:

    async def main():
        async with websockets.connect('ws:/ip.address:port') as ws:
            await send_messages(ws)
    
    async def send_messages(ws):
        await ws.send('TEST MESSAGE')
    
    
    loop = asyncio.get_event_loop()
    loop.run_until_complete(main)
    

    【讨论】:

    • 问题 - 我一开始没有这样做的原因是我需要两个函数永远运行 - 这不是必须等到 await send_messages(ws) 完成吗?
    • @JamesWilson 这真的取决于你想要达到的目标。但是你必须记住,如果你使用连接上下文(即async with 语句),所有的 websocket 操作都必须在这个上下文中发生。
    • 我正在尝试获得两个不会结束的函数(因为它们要么等待来自 asyncio.queue 的东西,要么等待来自 websocket 的东西或处理这些东西)继续运行同时并能够访问相同的 websocket。
    • @JamesWilson 一种可能的方法是在没有上下文的情况下创建 websocket (ws = websockets.connect([...]))。但可以说更好的方法是在连接上下文中处理正在运行的任务。例如,您可以考虑使用asyncio.waitasyncio.wait([func1(ws), func2(ws)])
    • @JamesWilson 这也应该有效。您可以将任务视为并发执行线程,这完全取决于您决定何时何地生成和等待这些任务。
    猜你喜欢
    • 2014-05-04
    • 2021-10-01
    • 1970-01-01
    • 2017-08-31
    • 2016-06-19
    • 1970-01-01
    • 2020-02-06
    • 1970-01-01
    • 2021-02-05
    相关资源
    最近更新 更多