首页 > 解决方案 > urwid + websockets + asyncio -- 服务器/客户端

问题描述

我想在客户端制作一个基于 websockets(服务器+客户端)和 urwid 用户界面的服务器/客户端程序。

我面临的问题是我不断收到“从未检索到任务异常”......我工作,但它不干净......

我的服务器:

import asyncio, websockets, random, json

connected = set()

##########################
# end-less loop routines
##########################

async def handle_read_external_data():
  # now sumulated by an asyncio sleep of 1 second and random generator
  await asyncio.sleep(1)
  data = {'value': (random.random() * 0.4) - 0.2 + 40}
  return data

async def broadcast_task():
  global connected
  while True:
    data = await handle_read_external_data()
    data_json = json.dumps(data)
    print ("len:", len(connected))
    if connected != set():
      try:
        await asyncio.wait([ws.send(data_json) for ws in connected])
      except Exception as e:
        print (e)

##########################
# websockets
##########################

async def consumer_handler(websocket, path):
  global connected
  # Register.
  connected.add(websocket)
  try:
    async for message in websocket:
      print (message)
  except Exception as e:
    print ("Unregister websocket")
    connected.remove(websocket)

##########################
# Asyncio event loop
##########################

def start_event_loop():
  loop = asyncio.get_event_loop()
  tasks = asyncio.gather(
        broadcast_task(),
        websockets.serve(consumer_handler, '0.0.0.0', 8765),
    )
  try:
    loop.run_until_complete(tasks)
  except Exception:
    print("exception consumed")
  except BaseException:
    print("caught BaseException!")
    raise
  finally:
    loop.close()

if __name__ == "__main__":
    start_event_loop()

我的客户:

import asyncio, websockets, json, urwid

loop = asyncio.get_event_loop()
evl = urwid.AsyncioEventLoop(loop=loop)
urwid_loop = None
tasks = None

txt = urwid.Text(u"Hello World")
fill = urwid.Filler(txt, 'top')

def show_or_exit(key):
    if key in ('q', 'Q'):
      global tasks
      tasks.cancel()
      raise urwid.ExitMainLoop()
    return key

async def consumer_handler():
    async with websockets.connect('ws://localhost:8765') as websocket:
      async for message in websocket:
        data = json.loads(message)
        txt.set_text ("data: {}".format (data['value']))


def main ():
  global urwid_loop, tasks, loop, evl

  urwid_loop = urwid.MainLoop(fill, event_loop=evl, unhandled_input=show_or_exit)
  urwid_loop.start()

  tasks = asyncio.gather(consumer_handler())

  try:
      loop.run_until_complete(tasks)
  except asyncio.CancelledError:
      pass

  urwid_loop.stop()
  loop.close()

if __name__ == "__main__":
    main()

当我启动服务器时,我得到:

len: 0
len: 0
len: 0
...

到目前为止,一切都很好。当我启动客户端时,服务器向我显示:

len: 0
len: 0
len: 1
len: 1
len: 1
...

目前我在客户端按下 CTRL+C 得到:

len: 1
Unregister websocket
len: 0

这是想要的行为,除了在客户端中我遇到异常并且我的终端“损坏”,因为它仍然处于“urwid”模式。

干净的退出,通过点击 Q 按钮,它会为客户端产生一个干净的退出,并且终端是好的。在服务器端,会出现“从未检索到任务异常”的消息,并且“已连接”变量仍然保存着关闭的 websocket。

Task exception was never retrieved
future: <Task finished coro=<WebSocketCommonProtocol.send() done, defined at ><path-to-python-install>/lib/python3.6/site-packages/websockets/protocol.py:325> exception=ConnectionClosed('WebSocket connection is closed: code = 1000 (OK), no reason',)>
Traceback (most recent call last):
  File "<path-to-python-install>/lib/python3.6/site-packages/websockets/protocol.py", line 334, in send
    yield from self.ensure_open()
  File "<path-to-python-install>/lib/python3.6/site-packages/websockets/protocol.py", line 470, in ensure_open
    raise ConnectionClosed(self.close_code, self.close_reason)
websockets.exceptions.ConnectionClosed: WebSocket connection is closed: code = 1000 (OK), no reason
len: 1
Task exception was never retrieved
...

任何人的线索?

标签: websocketserverclientpython-asynciourwid

解决方案


推荐阅读