如何在不停止反应器的情况下停止 websocket 客户端

How to stop a websocket client without stopping reactor

我在 python 中有一个类似于聊天室的应用程序,它打算执行以下操作:

  1. 提示用户输入 websocket 服务器地址。
  2. 然后创建一个连接到服务器和 send/receive 消息的 websocket 客户端。禁用创建 websocket 客户端的能力。
  3. 从服务器收到 "close" 后(不是关闭帧),客户端应断开连接并重新启用应用程序以创建客户端。回到 1.
  4. 如果用户退出应用程序,如果有一个 运行ning,它会退出 websocket 客户端。

我的方法是使用主线程来处理用户输入。当用户按下回车键时,将使用 AutoBahn 的扭曲模块为 WebSocketClient 创建一个线程,并将一个队列传递给它。检查 reactor 是否处于 运行ning 状态,如果不是,则启动它。 覆盖消息方法以在获取 "close" 时将关闭标志放入队列中。主线程会忙于检查Queue,直到收到标志并返回开始。代码如下所示。

主线程。

def main_thread():
    while True:
        text = raw_input("Input server url or exit")
        if text == "exit":
            if myreactor:
                myreactor.stop()
            break
        msgq = Queue.Queue()
        threading.Thread(target=wsthread, args=(text, msgq)).start()

        is_close = False
        while True:
            if msgq.empty() is False:
                msg = msgq.get()
                if msg == "close":
                    is_close = True
                else:
                    print msg
                if is_close:
                    break
        print 'Websocket client closed!'

工厂和协议。

class MyProtocol(WebSocketClientProtocol):
    def onMessage(self, payload, isBinary):
        msg = payload.decode('utf-8')
        self.Factory.q.put(msg)
        if msg == 'close':
            self.dropConnection(abort=True)

class WebSocketClientFactoryWithQ(WebSocketClientFactory):
    def __init__(self, *args, **kwargs):
        self.queue = kwargs.pop('queue', None)
        WebSocketClientFactory.__init__(self, *args, **kwargs)

客户端线程。

def wsthread(url, q):
    factory = WebSocketClientFactoryWithQ(url=url, queue=q)
    factory.protocol = MyProtocol
    connectWS(Factory)
    if myreactor is None:
        myreactor = reactor
        reactor.run()
    print 'Done'

现在我遇到了问题。看来我的客户端线程永远不会停止。即使我收到 "close",它似乎仍然是 运行ning,并且每次我尝试重新创建一个新客户端时,它都会创建一个新线程。我知道第一个线程不会停止,因为 reactor.run() 将永远 运行,但是从第二个线程开始,它应该是非阻塞的,因为我不再启动它了。我该如何改变它?

编辑:

我最终用

解决了它
  1. 断开连接后添加 stopFactory()
  2. 使用reactor.callFromThread()创建协议函数。
  3. 在第一个线程中启动反应器,将客户端放在其他线程中并使用 reactor.callInThread() 创建它们。

您的 main_thread 创建了新线程 运行 wsthreadwsthread 使用 Twisted APIs。 first wsthread 成为反应器线程。所有后续线程都是不同的,如果你使用它们的 Twisted API 会发生什么是不确定的。

您几乎肯定应该从您的应用程序中删除线程的使用。要在基于 Twisted 的应用程序中处理控制台输入,请查看 twisted.conch.stdio(不是 Twisted 的最佳文档部分,唉,但正是您想要的)。