我想在客户端制作一个基于 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
...
任何人的线索?