从其他线程关闭Python WebSocket服务器

ajsxfq5m  于 2023-06-29  发布在  其他
关注(0)|答案(2)|浏览(195)

我有一个WebSocket服务器类,它有一个stop()方法,当在控制台中按下Control+C时会调用该方法(所以我猜它是从另一个线程访问的)。
当调用stop()时,如何安全地停止服务器(并结束脚本的运行)?
当前的实现执行stop()方法,但是脚本继续运行并且不打印Server closed。但是如果客户端在调用stop()方法之后发送消息,那么脚本实际上完成并打印Server closed消息。

import asyncio
import websockets

DOMAIN = 'localhost'
PORT = 1111

class EchoServer:
    loop = None

    def stop(self): # METHOD CALLED FROM ANOTHER THREAD
        self.loop.stop()

    def process_message(self, message):
        print(message)
        return message

    async def handle(self, ws_client):
        print('Listening')
        async for message in ws_client:
            await ws_client.send(message)

    async def main(self):
        start_server = websockets.serve(self.handle, DOMAIN, PORT)
        asyncio.ensure_future(start_server)

    def start(self):
        self.loop = asyncio.get_event_loop()
        self.loop.create_task(self.main())
        print('Starting server...')
        self.loop.run_forever()

        print('Server closed')
disbfnqx

disbfnqx1#

尽管调用loop.stop最终会停止它-如果stop方法在循环自身的事件调度中执行,则它是立即的。
这可以通过循环本身的方法call_soon_threadsafe来完成:它将调度stop方法作为要由循环本身调用的任务。这个调用可以从你的控制器线程完成,没有任何问题。
因此,只需将您的stop方法更改为:

def stop(self): # METHOD CALLED FROM ANOTHER THREAD
        self.loop.call_soon_threadsafe(self.loop.stop)
svmlkihl

svmlkihl2#

在和我们的朋友ChatGPT聊了几句之后。我想到了一个解决办法:

import asyncio
import websockets

DOMAIN = 'localhost'
PORT = 1111

class EchoServer:
    loop = None

    def stop(self): # METHOD CALLED FROM ANOTHER THREAD
        self.isrunning = False
        if self.server:
            self.loop.call_soon_threadsafe(self.stop_event.set)
            self.loop.call_soon_threadsafe(self.server.close)
        else:
            print('Server closed')

    def process_message(self, message):
        print(message)
        return message

    async def handle(self, ws_client):
        print('Listening')
        async for message in ws_client:
            await ws_client.send(message)

    async def main(self):
        self.loop = asyncio.get_running_loop()
        self.stop_event = asyncio.Event()
        self.server = await websockets.serve(self.handle, DOMAIN, PORT)
        print('Server started')
        await self.stop_event.wait()
        print('Server stop')

    def start(self):
        asyncio.run(self.main())
        print('Server closed')

相关问题