urwid + websockets + asyncio - сервер / клиент - PullRequest
0 голосов
/ 11 мая 2018

Я хочу сделать программу сервер / клиент на основе веб-сокетов (сервер + клиент) и пользовательского интерфейса 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, он дает чистый выход для клиента,и терминал в порядке.На стороне сервера появляется сообщение " Исключение задачи не было получено ", а переменная "connected" по-прежнему содержит закрытый веб-сокет.

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
...

Кто-нибудь знает?

...