为什么我不能在协程调用的协程中发送 websocket? [英] Why can't I send down a websocket in a coroutine called by a coroutine?

查看:28
本文介绍了为什么我不能在协程调用的协程中发送 websocket?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为什么:

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 发送消息并:

send a message down the websocket and:

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') 部分,因为打开日志记录、调试等.

I've cut down the code from my code to simplify it - can post the original if necessary. The second version seems to hang at the await ws.send('test') part from turning on logging, debugging etc.

我想知道将 websocket 连接作为参数传递是否有问题.如果您记录传递的内容和在那里收到的内容,它们都会返回 两次,地址相同.

I wondered if it was an issue with passing the websocket connection as an argument. If you log what is passed and what is received there, they both return <websockets.client.WebSocketClientProtocol object at 0x04B51A90> with the same address both times.

我最终想要做的,以及如何做到这一点的建议,即使无法回答是:

What I ultimately want to do, and suggestions for how to do this are welcome even if the question can't be answered is:

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

Have two coroutines running, pretty much forever that: * take messages from a queue put there by regular functions from the tkinter GUI and send them down the websocket * take messages from the websocket and alter things in the GUI

我认为作为 asyncio 的 websockets 库可以做到这一点,但我愿意接受任何建议.

I thought the websockets library as asyncio would be the way to do this, but am open to any suggestions.

忘记添加错误信息!

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.

推荐答案

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

It is fine to pass the websocket as an argument. The problem here is that the websocket connection is already closed when the send coroutine is awaited (as explained in your error message). That happens because the connection context finishes before the send_messages task can send the message.

相反,请考虑以下工作示例:

Instead, consider this working example:

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)

这篇关于为什么我不能在协程调用的协程中发送 websocket?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆