2010-09-11 84 views
0

我正在嘗試使用pyGTK,treads和套接字來構建Python應用程序。我有這個奇怪的錯誤,但考慮到所有的模塊,我不完全確定錯誤在哪裏。我做了一些調試與一些打印語句,以縮小東西下來了一點,我認爲錯誤是在這個代碼片段的話:Python GTK /線程/套接字錯誤

self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
    self.sock.connect(("localhost", 5005)) 
    self.collectingThread = threading.Thread(target=self.callCollect) 
    self.collectingThread.daemon = True 
    self.collectingThread.start() 

def callCollect(self): 
    gobject.timeout_add(500, self.collectData) 

def collectData(self): 
    print "hello" 
    try: 
     print self.sock.recv(1024) 
    except: 
     print "except" 
    print "return" 
    return True 

所以基本上我想要做的是設置一個插座,連接到一個「服務器」腳本(這實際上只是另一個在本地運行的python腳本),並創建一個單獨的線程來收集來自服務器腳本的所有傳入數據。該線程設置爲每500毫秒運行一次collectData方法。

插入打印語句到collectData方法這裏之後是我注意到運行程序時:

-Initially的GUI是全功能的

- 然後被印刷在所述終端執行以下操作:

hello 
**all data received from server script and printed here** 
return 
hello 

-after文本被在終端印刷中,GUI變得完全非功能性的(按鈕不能被按壓等),並且我不得不強制退出關閉應用程序

似乎正在發生的事情是線程打印「hello」,打印來自服務器的數據,並打印「返回」。 500毫秒後,它再次運行collectData方法,打印「hello」,然後嘗試從服務器打印數據。但是,由於沒有數據,所以會引發異常,但由於某些未知原因,它不會執行異常塊中的代碼,並且所有內容都會從此處掛起。

有什麼想法出錯了?

回答

1

timeout_add是調度的動作主線程上發生將套接字設置爲非阻塞。

您需要將接收委託給預定動作中的線程而不是反之亦然,以獲得您所追求的效果。等待一個事件對象,並且每500毫秒計劃一次該事件的信號。

+1

它是「timeout_add」,而不是「timeout_call」。 – AndiDog 2010-09-11 23:40:22

+0

@安迪,哎呀,謝謝,編輯修復思想;-)。 – 2010-09-11 23:45:04

+0

如何明確地告訴次要線程等待事件對象及其相應的信號?我檢查了pyGTK教程中的不同事件,但在插座上找不到任何東西。對不起,我對pyGTK很陌生。 – pythonBOI 2010-09-12 03:34:17

0

不,顯然是sock.recv調用塊,因爲套接字尚未關閉,並且套接字接收默認爲阻塞。確保您在某個時候關閉連接。

在新線程中運行接收調用會更有意義,否則它可能會阻止GUI,因爲當前實現在GUI線程中使用recv調用(使用timeout_add)。您目前的做法只有在答案得到非常快速和/或您必須訪問小部件時纔有意義。

順便說一下,創建一個用於調用gobject.timeout_add的新線程是完全沒有必要的。 timeout_add()idle_add()註冊指定的回調函數並立即返回。 GTK事件循環會在超時後自動執行回調(或處於空閒狀態idle_add)。除非你把超時左右recv只有幾個街區的主線程(當它只是在等待數據),因此GUI,因此,也不例外 -

+0

只需將套接字設置爲非阻塞並將所有內容保留在同一個線程中就足夠了嗎?我可以讓套接字打開(這樣它可以繼續接收數據)並在用戶試圖關閉窗口時關閉它? – pythonBOI 2010-09-12 03:48:01

+0

@pythonBOI:這可能更像是一種黑客攻擊,但是如果你沒有那麼多的套接字,它就會起作用。您無法打開無限數量的套接字,因此您應該在某個時候關閉套接字。我不知道你使用的是哪種通信協議,所以我無法幫助你。 – AndiDog 2010-09-12 09:06:02