【问题标题】:Closing/Shutting down a Python Websocket关闭/关闭 Python Websocket
【发布时间】:2020-07-23 00:02:48
【问题描述】:

我扩展了 websocket 回显服务器示例 (here),使其嵌入到 Tkinter 应用程序中。当按下“开始”按钮时,服务器将启动。现在我想在按下“停止”按钮时停止服务器。但是,close() 不起作用。

server.py:

try:
    import Tkinter as Tk
    from Tkinter import ttk
except ModuleNotFoundError:
    import tkinter as Tk
    from tkinter import ttk

import asyncio
import websockets


class TkEcho():
    def __init__(self):
        asyncio.get_event_loop().run_until_complete(self.main())


    async def main(self):
        '''
        Add Buttons
        '''
        root = Tk.Tk()

        Tk.Button(root, text='Start', command=lambda: self.start("localhost", 8765)).grid()
        Tk.Button(root, text='Stop', command=self.stop).grid()

        await self.run_tk(root)


    async def run_tk(self, root, interval=0.05):
        '''
        Add Tk to asyncio
        '''
        try:
            while True:
                root.update()
                await asyncio.sleep(interval)
        except Tk.TclError as e:
            if "application has been destroyed" not in e.args[0]:
                raise


    async def echo(self, websocket, path):
        '''
        Receives string and sends it back to sender
        '''
        string = await websocket.recv()
        print(f"recv < {string}")
        await websocket.send(string)
        print(f"send > {string}")


    def start(self, host, port):
        '''
        Starts websocket
        '''
        start_server = websockets.serve(self.echo, host, port)
        asyncio.ensure_future(start_server)


    def stop(self):
        '''
        Stops websocket
        '''
        None


if __name__ == "__main__":
    t = TkEcho()

client.py:

import asyncio
import websockets

    async def send_recv():
    uri = "ws://localhost:8765"
    async with websockets.connect(uri) as websocket:
        string = input("string to send? ")

        await websocket.send(string)
        print(f"send> {string}")

        string = await websocket.recv()
        print(f"recv< {string}")

asyncio.get_event_loop().run_until_complete(send_recv())

解决方案:

TkEcho.__init__ 替换为:

def __init__(self):
    loop = asyncio.get_event_loop()
    loop.create_task(self.main())
    loop.run_forever()

并按如下方式实现TkEcho.stop

def stop(self):
    '''
    Stops websocket
    '''
    asyncio.get_event_loop().stop()

【问题讨论】:

  • 你在stop的定义中尝试过类似asyncio.get_event_loop().stop()的东西吗?这将停止事件循环,并扩展程序的其余部分和服务器。
  • 我刚试过。它导致RuntimeError 并使整个应用程序崩溃。它停止了事件循环,但服务器仍在运行:RuntimeError: Event loop stopped before Future completed.
  • 错误是由于你如何启动事件循环;您可以通过将__init__ 中的代码替换为loop = asyncio.get_event_loop(); loop.create_task(self.main()); loop.run_forever() 来修复它。

标签: python websocket python-asyncio


【解决方案1】:

要停止程序,您可以简单地停止事件循环:

    def stop(self):
        # terminate the loop
        asyncio.get_event_loop().stop()

为此,您需要使用run_forever() 而不是run_until_complete() 来运行事件循环:

    def __init__(self):
        loop = asyncio.get_event_loop()
        loop.create_task(self.main())
        loop.run_forever()  # wait for loop.stop() to terminate us

【讨论】:

  • 我之前在连接到服务器时使用了 loop.close(),它抛出了运行时错误。但是先使用 loop.stop() 然后使用 loop.close(),优雅地终止循环。只是我的经验。
猜你喜欢
  • 2016-03-29
  • 2012-02-21
  • 1970-01-01
  • 1970-01-01
  • 2021-03-25
  • 2022-10-06
  • 2014-12-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多