我正在尝试使用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方法。
将print语句插入collectData方法后,这是我在运行程序时注意到的:
- 最初GUI功能齐全
- 然后在终端中打印以下内容:
hello
**all data received from server script and printed here**
return
hello
- 在终端中打印文本后,GUI变得完全无法使用(按钮无法按下等),我必须强制退出以关闭应用程序
似乎正在发生的是线程打印“hello”,从服务器打印数据,并打印“return”。 500毫秒后,它再次运行collectData方法,打印“hello”,然后尝试从服务器打印数据。但是,由于没有数据,它会引发异常,但由于某些未知原因,它不会在异常块中执行代码,并且所有内容都会从那里挂起。
关于出了什么问题的任何想法?
答案 0 :(得分:1)
timeout_add
正在安排行动在主线程上发生 - 所以recv
只是阻塞主线程(当它只是在等待数据时),因此GUI,所以,除非你设置超时或将套接字设置为非阻塞,否则没有异常。
你需要将接收委托给来自计划行动的线程,而不是反之,以获得你所追求的效果:拥有线程,例如:等待一个事件对象,并且计划的动作每500毫秒发出一次该事件的信号。
答案 1 :(得分:0)
不,显然sock.recv
调用块因为套接字尚未关闭而套接字接收默认为阻塞。确保在某个时刻关闭连接。
在新线程中运行receive调用会更有意义,否则它可能会阻止GUI,因为当前实现在GUI线程中运行recv
调用(使用timeout_add
)。您目前正在进行此操作的方式只有在收到答案非常快且/或您必须访问小部件时才有意义。
顺便说一下,创建一个用于调用gobject.timeout_add
的新线程是完全没必要的。 timeout_add()
和idle_add()
注册指定的回调函数并立即返回。 GTK事件循环然后在超时(或idle_add
的空闲状态)后自动执行回调。