2017-09-16 69 views
1

我有類似蟒蛇聊天室編寫打算做以下事情的應用程序:如何停止的WebSocket客戶端無需停​​止反應堆

  1. 對用戶輸入的WebSocket服務器地址的提示。
  2. 然後創建一個連接到服務器併發送/接收消息的websocket客戶端。禁用創建websocket客戶端的功能。
  3. 在收到服務器的「關閉」(不是關閉幀)後,客戶端應該斷開連接並重新啓用應用程序以創建客戶端。返回1.
  4. 如果用戶退出應用程序,它將退出websocket客戶端(如果有一個正在運行)。

我的方法是使用主線程來處理用戶輸入。當用戶輸入時,使用AutoBahn的扭曲模塊爲WebSocketClient創建一個線程,並將一個隊列傳遞給它。檢查反應堆是否在運行,如果不是,則啓動反應堆。 覆蓋消息方法以在「關閉」時將關閉標誌放入隊列中。主線程將忙於檢查隊列,直到收到標誌並返回開始。代碼如下所示。

主線程。

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」,它似乎仍在運行,每次我嘗試重新創建一個新客戶端時,它都會創建一個新線程。我知道第一個線程不會停止,因爲reactor.run()將永遠運行,但從第二個線程開始,它應該是非阻塞的,因爲我不再啓動它。我該如何改變它?

編輯:

我結束了

  1. 斷開連接後添加stopFactory()解決它。
  2. 使協議功能與reactor.callFromThread()
  3. 在第一個線程中啓動反應器並將客戶端放入其他線程並使用reactor.callInThread()來創建它們。
+0

服務器可以關閉客戶端套接字,是否要處理服務器上的所有客戶端錯誤? – dsgdfg

+0

@dsgdfg事實是,我試圖複製一個現有的應用程序,但我沒有自己的客戶端或服務器,所以我沒有代碼。從我所知道的使用wireshark,我可以看到服務器發送消息「關閉」,客戶端回覆代碼爲1001的關閉幀並退出。我想要做同樣的事情,但我不知道如何關閉客戶端並讓線程返回,以便我可以做其他工作。 – vance46

回答

0

您的main_thread創建運行wsthread的新線程。 wsthread使用Twisted API。 第一個wsthread成爲反應器線程。所有後續的線程是不同的,它是不確定的,如果你使用它們的Twisted API會發生什麼。

你應該幾乎可以肯定地從應用程序中刪除使用線程。要處理基於Twisted的應用程序中的控制檯輸入,請查看twisted.conch.stdio(不是扭曲的最好記錄部分,唉,但正是你想要的)。

+0

謝謝指出!我認爲這可能是問題。我明白,使用單線程可能適合Twisted更好,但我需要做一些事情 - >啓動websocket客戶端 - >根據結果做一些事情,重複。據我所知,我需要做reactor.run()來啓動websocket客戶端,但它會永遠阻塞。沒有使用線程有沒有更好的方法可以做到以上?我也有一個GUI線程,我不知道沒有多線程是不是很好。 – vance46

+0

Twisted具有各種GUI集成功能。根據哪個工具包,您可能能夠找到一種方法來在單個線程中運行GUI和Twisted。另外,如果您熟悉GUI編程(無論如何不需要額外的線程),那麼很多這些想法也適用於Twisted。例如,你不要在Tkinter中編寫'while True:'循環...你使用'after_idle' API。同樣,Twisted也有API,允許你安排更多的代碼稍後運行,以避免產生阻塞反應器線程的循環(並且避免被'reactor.run'塊阻塞)。 –