0

在这一点上,当谈到 GUI 和网络编程时,我仍然是一个菜鸟,所以我希望这将是一个非常简单的修复。我对 tkinter 和 asyncore 模块有一个非常基本的了解,它们在每个模块中都构建了一些程序,但是我在一个程序中同时使用它们时遇到了麻烦。我拼凑了一个完整的 UI,却发现我无法实现任何重要的异步网络功能。为了简单起见,我将程序解构为最简单的形式来说明我遇到的基本问题。继承人的代码:

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 方法并在服务器上执行了一个命令(将数据发送回客户端),这个方法也不会被调用。我认为有一些普遍的问题会阻止异步循环自行运行。我意识到 tkinter 事件循环可能是罪魁祸首,但我的印象是 after_idle 方法将允许在 GUI 空闲时处理非 Tkinter 事件。是仍然导致问题的 tkinter 事件循环还是其他原因?

4

2 回答 2

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 中放置一个异常处理程序。初始化,看看你怎么样。

于 2010-01-01T12:19:25.777 回答
0

请参阅Jacob Hallén 的这个配方,展示如何一起使用 asyncore 和 Tkinter(基本上是通过线程技巧)。(它还在 Python Cookbook 的第一版印刷版中扩展为配方 9.6,在第二版中扩展为 11.4)。

于 2010-01-01T17:40:00.270 回答