Asyncore在Tkinter GUI中无法正常工作

0 投票
1 回答
1306 浏览
提问于 2025-04-15 17:31

目前我在图形用户界面(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 个回答

2

这里有几个问题,我也不太确定具体是哪一个。

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 中加一个异常处理器,看看结果如何。

撰写回答