Python GTK/线程/套接字错误

1 投票
2 回答
1077 浏览
提问于 2025-04-16 04:01

我正在尝试用pyGTK、线程和套接字来构建一个Python应用程序。遇到了一个奇怪的错误,但由于涉及的模块比较多,我不太确定错误出在哪里。我加了一些打印语句来调试,想缩小问题范围,我觉得错误可能出现在这段代码中:

    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方法中插入打印语句后,我在运行程序时注意到以下几点:

- 一开始,图形界面(GUI)是完全正常的

- 然后终端打印出了以下内容:

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

- 在终端打印完这些文本后,图形界面就完全失去了响应(按钮无法点击等),我不得不强制退出才能关闭应用程序

看起来发生的情况是,线程打印“hello”,然后打印服务器的数据,最后打印“return”。500毫秒后,它再次运行collectData方法,打印“hello”,然后尝试打印服务器的数据。然而,由于没有剩余的数据,它抛出了一个异常,但由于某种未知原因,它没有执行异常处理块中的代码,结果程序就卡住了。

你觉得问题出在哪里呢?

2 个回答

0

不,显然,sock.recv 这个调用会阻塞,因为套接字还没有关闭,而套接字接收默认是阻塞的。确保你在某个时候关闭连接。

把接收的调用放在一个新线程里会更合理,否则可能会阻塞图形界面,因为你现在的实现是在图形界面的线程中运行 recv 调用(使用 timeout_add)。你现在的做法只有在快速收到答案和/或需要访问界面组件时才有意义。

顺便说一下,为了调用 gobject.timeout_add 创建一个新线程是完全不必要的。timeout_add()idle_add() 会注册指定的回调函数并立即返回。GTK事件循环会在超时后自动执行这个回调(或者在空闲状态下对于 idle_add)。

1

timeout_add 是在主线程上安排某个动作的执行,所以当 recv 在等待数据时,它会阻塞主线程,这样就会导致图形界面(GUI)也卡住。因此,除非你设置了超时或者把套接字设置为非阻塞,否则不会出现异常。

你需要把接收数据的任务交给一个线程,而不是反过来,这样才能达到你想要的效果:让这个线程等待一个事件对象,然后每500毫秒由安排的动作来触发这个事件。

撰写回答