2010-01-01 128 views
0

在這一點上,當談到GUI和網絡編程,我仍然是一個小菜鳥,所以我希望這將是一個非常簡單的修復。我已經對tkinter和asyncore模塊有了非常基本的瞭解,並在每個模塊中都構建了一些程序,但是我在使用它們時遇到了麻煩。我把整個用戶界面放在一起,只是發現我無法實現任何重要的異步網絡功能。爲了簡單起見,我將程序解構成最簡單的形式來說明我遇到的基本問題。繼承人的代碼:Asyncore無法正常工作與Tkinter GUI

from Tkinter import * 
import asyncore, socket 

class Application(object): 
    def __init__(self, root): 
     mainFrame = Frame(root) 
     mainFrame.grid(column=1, row=1, columnspan=3, rowspan=1) 
     mainButton = Button(mainFrame, text='Click', command=self.makeSocket) 
     mainButton.grid(column=2, row=1, columnspan=1, rowspan=1, pady=7, padx=40) 

    def makeSocket(self): 
     clientSocket() 

class clientSocket(asyncore.dispatcher): 
    def __init__(self): 
     asyncore.dispatcher.__init__(self) 
     self.create_socket(socket.AF_INET, socket.SOCK_STREAM) 
     self.connect(("XXX.XXX.XXX.XXX", XXXX)) 
     print 'init works' 

    def handle_connect(self): 
     print 'connect works' 

root = Tk() 
myApp = Application(root) 
root.after_idle(asyncore.loop) 
root.mainloop() 

所以,當我運行該程序,並單擊該按鈕,我得到的字符串「初始化工作」,表明ClientSocket的對象進行初始化,連接成功。但是,handle_connect方法不運行。如果我實現handle_read方法並在服務器上執行一個命令(將數據發送回客戶端),也不會調用此方法。我在想,有一些常規問題會阻止asyncore循環自行運行。我意識到tkinters事件循環可能是罪魁禍首,但我的印象是after_idle方法會允許在GUI空閒時處理非Tkinter事件。 tkinter事件循環是否仍然會導致問題,或者可能是其他問題?

+0

對於它的價值,asyncore是一種非常古老而笨重的Python技術,雖然仍然處於標準庫中以兼容性,但對於現代項目而言,這是一個相當差的選擇。如果你想要一個更好的異步框架,試試Twisted Python。 (我不建議輕輕扭曲!) – 2010-10-21 13:27:24

回答

2

這裏有幾個問題,我不確定它是哪一個。

asyncore.loop是一個從不返回的函數,當事情正常工作。 root.mainloop可能是一個函數,直到關閉窗口才會返回。所以事情可能會出錯,因爲在某個時間點,一個循環會被另一個循環餓死。 (順便說一下,這就是爲什麼我不喜歡通過替換主循環並用事件驅動系統替換它的嘗試使它們的使用更容易的框架 - 它非常適用,直到您需要將兩個或多個這些系統一起使用,此時事情可能會變得混亂。)

但是,您可以限制asyncore.loop將迭代的次數。試試這個:

def poll_asyncore_once(): 
    asyncore.loop(count=1) 

root.after_idle(poll_asyncore_once) 

你也許想給循環調用增加一個超時值,小於一秒。

但是,即使GUI由於進入asyncore循環而最終導致事件中斷,我仍然認爲連接最終會通過。這意味着其他的東西出了問題,並且asyncore可能會在connect()方法中引發異常,並且TK正在吞嚥它。嘗試在clientSocket中放置一個異常處理程序。 init並看看你如何去。

+0

我添加了異常處理程序,它看起來像連接成功發生。我會仔細研究Alex下面鏈接的食譜,但出於好奇,我怎麼能創建我想要的程序而不使用任何偶驅動的框架?如果我理解正確,asyncore全部基於select()和poll()函數。那麼我只需要學習如何使用這些並創建適合GUI的自己的循環呢?我會用什麼來製作GUI本身?我會用TK和Tcl來做它,還是有更好的方法來做到這一點? – HoboMo 2010-01-02 05:16:27

+0

如果使用count參數作爲asyncore.loop,它實際上會成爲一個帶有回調而不是事件驅動系統的輪詢系統,這樣問題的一面就會消失。雖然我不能對Tkinter發表評論 - 基於GUI的系統傾向於基於事件,因爲它與它們基於的典型消息隊列系統相匹配。只要它方便您使用空閒時間,它可能就沒問題。 – Kylotan 2010-01-03 01:09:28

+0

至於你的實際問題,我不相信把任何東西放入不同的線程將解決它(儘管它可能是一個更好的解決方案,其他原因,例如響應)。我試圖修改我自己的asyncore副本來添加額外的日誌記錄(儘管我似乎記得有一些日誌鉤子已經在那裏可以使用),並找出爲什麼handle_connect沒有被調用。 – Kylotan 2010-01-03 01:10:30

0

請參閱JacobHallén的this recipe,其中展示瞭如何一起使用asyncore和Tkinter(基本上通過線程技巧)。 (它也在Python Cookbook的第一版中作爲配方9.6擴展,在第二版中作爲11.4擴展)。

+0

AFAICS它是Python Cookbook第二版中的第11.9節 – 2011-05-17 12:31:35

+0

該配方完全不使用asyncore。 – 2011-06-17 03:42:36