python Websockets(asyncio ver)强制关闭连接

时间:2018-06-29 20:57:13

标签: python-3.x websocket python-asyncio

我正在为python> 3.5进行编码。 我正在使用Websockets 6.0库,在这里:   https://github.com/aaugustin/websockets 我一直称它们为Image Out[42]: b'iVBORw0KGgoAAAANSUhEUgAAAKAAAAB4CAAAAABQyaazAAAgAElEQVR4ARzB68............................. Websocket,因为它们基于asyncio。 在我的搜索中,有很多“丢失的连接”,但是我正在研究如何取消当前的asyncio。 调用ws.recv()会创建一个帮助线程,以启动asynico事件循环。然后,接收函数启动并调用connect函数,并实例化了websocket .start()。然后,接收功能将处理掉落消息。当我准备停止时,将调用.stop()。我期望停止功能可以停止等待的ws。然后,将keep_running标志设置为false并运行ws.recv(),我希望ws.close()结束,而when keep_running循环结束。那不是正在发生的事情。我看到了所有三个停靠点,但没有看到ws.recv()

receive stop

参考代码:

command is: stop
Do command is stopped
Stop 1
Stop 2
Stop 3
^CException ignored in: <module 'threading' from '/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/threading.py'>
Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/threading.py", line 1294, in _shutdown
    t.join()
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/threading.py", line 1056, in join
    self._wait_for_tstate_lock()
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/threading.py", line 1072, in _wait_for_tstate_lock
    elif lock.acquire(block, timeout):
KeyboardInterrupt
(pyalmondplus) Pauls-MBP:pyalmondplus paulenright$ 

1 个答案:

答案 0 :(得分:0)

  

我正在研究如何取消当前的ws.recv()[...]我看到了所有三个停靠点,但是没有收到停靠点。

您的receive协程可能会暂停,以等待某些数据到达,因此无法检查keep_running标志。

停止协程运行的简单而可靠的方法是cancel驱动它的异步Task。这将立即取消协程的暂停,并使其等待的所有内容都产生CancelledError。使用取消时,您根本不需要keep_running标志,该异常将自动终止循环。

  

对.start()的调用将创建一个帮助程序线程以启动asynico事件循环。

这有效,但是对于PyAlmondPlus的每个实例,您实际上并不需要新的线程和全新的事件循环。 Asyncio设计为在单个线程中运行,因此一个事件循环实例可以承载任意数量的协程。

这是一个可以同时实现这两种想法的设计(未经实际的Web套接字测试):

# pre-start a single thread that runs the asyncio event loop
bgloop = asyncio.new_event_loop()
_thread = threading.Thread(target=bgloop.run_forever)
_thread.daemon = True
_thread.start()

class PyAlmondPlus:
    def __init__(self, api_url):
        self.api_url = api_url
        self.ws = None

    async def connect(self):
        if self.ws is None:
            self.ws = await websockets.connect(self.api_url)

    async def receive(self):
        # keep_running is not needed - cancel the task instead
        while True:
            if self.ws is None:
                await self.connect()
            recv_data = await self.ws.recv()

    async def init_receive_task(self):
        self.receive_task = bgloop.create_task(self.receive())

    def start(self):
        # use run_coroutine_threadsafe to safely submit a coroutine
        # to the event loop running in a different thread
        init_done = asyncio.run_coroutine_threadsafe(
            self.init_receive_task(), bgloop)
        # wait for the init coroutine to actually finish
        init_done.result()

    def stop(self):
        # Cancel the running task. Since the event loop is in a
        # background thread, request cancellation with
        # call_soon_threadsafe.
        bgloop.call_soon_threadsafe(self.receive_task.cancel)
相关问题