Why can't I send down a websocket in a corouti

2019-07-25 17:29发布

问题:

Why does:

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()

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()

doesn't?

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.

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:

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

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

EDIT: forgot to add the error message!

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.

回答1:

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)