Asyncore在Tkinter GUI中无法正常工作
目前我在图形用户界面(GUI)和网络编程方面还是个新手,所以希望这个问题能很简单地解决。我对tkinter和asyncore这两个模块有一些基本的了解,之前也写过几个小程序,但我在把这两个模块结合在一起使用时遇到了麻烦。我搭建了一个完整的用户界面,结果发现无法实现任何有效的异步网络功能。为了简单起见,我把程序简化到最基本的形式,以便说明我遇到的主要问题。以下是代码:
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()
当我运行程序并点击按钮时,看到字符串'init works',这说明clientSocket对象已经初始化,连接也成功建立了。但是,handle_connect这个方法并没有运行。如果我实现了handle_read方法并在服务器上执行一个命令(让它把数据发送回客户端),这个方法也没有被调用。我在想,可能有某个普遍的问题导致asyncore循环无法独立运行。我意识到tkinter的事件循环可能是罪魁祸首,但我原以为after_idle方法可以在GUI空闲时处理非Tkinter的事件。是tkinter的事件循环仍然造成了问题,还是其他什么原因呢?
1 个回答
这里有几个问题,我也不太确定具体是哪一个。
asyncore.loop 是一个不会返回的函数,正常情况下它会一直运行下去。root.mainloop 也是一个类似的函数,直到你关闭窗口它才会停止。所以很可能会出现问题,因为在某个时刻,一个循环会被另一个循环拖慢,导致它无法正常工作。
顺便说一下,这也是我不喜欢那些试图通过替换主循环来简化使用的框架的原因——它们在单独使用时效果很好,但当你需要将两个或多个这样的系统一起使用时,事情就会变得很复杂。
不过,你可以限制 asyncore.loop 运行的次数。试试这个:
def poll_asyncore_once():
asyncore.loop(count=1)
root.after_idle(poll_asyncore_once)
你可能还想给循环调用添加一个超时值,设置成小于一秒的时间。
不过,我本来以为即使因为进入 asyncore 循环导致 GUI 没有事件,连接最终还是会成功的。这说明可能还有其他问题,可能是 asyncore 在 connect() 方法中抛出了异常,而 TK 没有处理这个异常。试着在 clientSocket.init 中加一个异常处理器,看看结果如何。