2011-11-26 52 views
0

SocketClientThread參考:http://eli.thegreenplace.net/2011/05/18/code-sample-socket-client-thread-in-python/多個螺紋套接字連接/隊列

以利提供瞭如何管理一個插座客戶線程內,並傳送到與該隊列模塊的主要範圍這個通用例子。 (再次感謝Eli!)

一個線程工作的很好,但我試圖做的是同時管理多個SocketClientThread對象。

連接後,當我嘗試發送數據到第二個對象時,它告訴我SocketClientThread.socket沒有sendall屬性,所以我認爲套接字被取消。

1和2的服務器都成功接收連接,但它是觸發錯誤的第二個服務器的發送命令。

如何重新使用這個類與多個對象?

下面是輸出:

$ python testmodule.py 
('sct1: ', 1, None) 
('sct1: ', 1, 'tuxy') 
('sct2: ', 1, None) 
Exception in thread Thread-2: 
Traceback (most recent call last): 
    File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/threading.py", line 522, in __bootstrap_inner 
    self.run() 
    File "testmodule.py", line 59, in run 
    self.handlers[cmd.type](cmd) 
    File "testmodule.py", line 115, in _handle_SEND 
    self.socket.sendall(header + cmd.data) 
AttributeError: 'NoneType' object has no attribute 'sendall' 

,這裏是試圖打開我的兩個代碼:

if __name__ == "__main__": 
    sct1 = SocketClientThread() 
    sct1.start() 
    sct1.cmd_q.put(ClientCommand(ClientCommand.CONNECT, ('', 50007))) 
    reply = sct1.reply_q.get(True) 
    sct1.cmd_q.put(ClientCommand(ClientCommand.SEND, "hellothere from sct1")) 
    reply = sct1.reply_q.get(True) 
    print('sct1: ', reply.type, reply.data) 
    sct1.cmd_q.put(ClientCommand(ClientCommand.RECEIVE, "hellothere from sct1")) 
    reply = sct1.reply_q.get(True) 
    print('sct1: ', reply.type, reply.data) 

    sct2 = SocketClientThread() 
    sct2.start() 
    sct2.cmd_q.put(ClientCommand(ClientCommand.CONNECT, ('', 50008))) 
    reply = sct2.reply_q.get(True) 
    print('sct2 connect: ', reply.type, reply.data) 
    sct2.cmd_q.put(ClientCommand(ClientCommand.SEND, "hellothere from sct2")) 
    reply = sct2.reply_q.get(True) 
    print('sct2 send: ', reply.type, reply.data) 
    sct2.cmd_q.put(ClientCommand(ClientCommand.RECEIVE, "hellothere from sct2")) 
    reply = sct2.reply_q.get(True) 
    print('sct2: ', reply.type, reply.data) 

    #close connection 1 
    sct1.cmd_q.put(ClientCommand(ClientCommand.CLOSE)) 
    reply = sct1.reply_q.get(True) 
    print('sct1 close: ', reply.type, reply.data) 

    #close connection 2 
    sct2.cmd_q.put(ClientCommand(ClientCommand.CLOSE)) 
    reply = sct2.reply_q.get(True) 
    print('sct2 close: ', reply.type, reply.data) 

回答

2

看起來您已經在示例代碼中發現了一個錯誤:-)只有當您同時創建多個線程時纔會發生該錯誤,如您所注意的。這是因爲Queue.Queue()默認參數只在類定義時才構造 - 這實際上是Python中的一個常見錯誤,但通常發生在列表中。

我已經更新了帖子,但不變的是在這裏:

def __init__(self, cmd_q=None, reply_q=None): 
    super(SocketClientThread, self).__init__() 
    self.cmd_q = cmd_q or Queue.Queue() 
    self.reply_q = reply_q or Queue.Queue() 
    self.alive = threading.Event() 
    self.alive.set() 
    self.socket = None 

    self.handlers = { 
     ClientCommand.CONNECT: self._handle_CONNECT, 
     ClientCommand.CLOSE: self._handle_CLOSE, 
     ClientCommand.SEND: self._handle_SEND, 
     ClientCommand.RECEIVE: self._handle_RECEIVE, 
    } 

注意隊列如何現在初始化 - 這是一個常見的成語,以避免可變默認參數的疑難雜症。

示例代碼現在工作對我來說


附:在我的Windows機器上,我必須在客戶端指定主機(即使它是localhost)才能成功連接。

+0

我不能夠感謝你。我確認我的套接字和隊列現在都按預期工作。隊列的創建方式讓人想起,但我無法理解如何殺死套接字。我看到他們共享相同的隊列對象。謝謝! – Coder1

+0

@ Coder1:是的,所以另一個線程得到了殺死第一個套接字的請求,並且終止了它自己的套接字,但之後得到了發送/接收請求... –

+0

不應該只是能夠調用從它的父對象mysocketclientthread.join()終止線程?我已經嘗試了這一點,並添加了加入隊列處理程序。該應用程序掛起,似乎父對象變得未設置。也許不是一個好評的話題。 – Coder1

0

對於多線程使用套接字線程/進程之間的通信我會建議您嘗試ZeroMQ編程。它使異步I/O變得簡單,並具有內置的自動排隊功能。讓多個線程同時向GUI線程發送消息是微不足道的,並且消息在到達時排隊並處理。我希望這有幫助。