wxReactor 问题

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

我正在开发一个使用Twisted和wxReactor的程序。每次我尝试退出应用程序时,它都会卡住,我不得不强制关闭它。我的wxPython的OnClose()事件确实调用了reactor.stop(),据我所知,这应该能解决这个问题。在寻找答案的过程中,我发现了这个问题单: www.twistedmatrix.com/trac/ticket/3948。
我尝试了页面上列出的一个补丁,但没有成功。我已经为这个问题纠结了两周,现在真的很绝望 :)。

为了让大家了解这个项目的背景:这是一个免费软件客户端,使用套接字连接到一个多人游戏服务器(目前支持大富翁和UNO)。如果你运行它,你会立刻注意到没有图形界面。这是因为这个客户端只通过语音合成和音效提供音频反馈。这个项目的目标用户是视力障碍的玩家。

要测试这个问题,可以运行python rsg.py(这个文件在src文件夹里。如果你需要知道,我使用的是Python 2.6.5)。在终端中,你会看到程序输出的内容(主要是服务器发送给我们客户端的信息)。当你看到“Connection Made”这一行(这行应该在运行后很快就会出现)时,尝试关闭程序(点击X)。客户端会卡住几秒钟,然后你需要强制关闭应用程序(在Ubuntu上,它会询问我是否要强制关闭应用程序)。

我大致知道为什么它不能正常退出。当我通过gdb运行它时,有两个线程没有退出。奇怪的是,如果服务器关闭了连接,然后我退出程序,它就能正常工作。

我非常感谢大家的帮助。提前谢谢你们。

编辑 由于有人要求我提供一个基本的演示来说明我的问题,这里就是:

import wx
import sys
from twisted.internet import wxreactor
wxreactor.install()

# import t.i.reactor only after installing wxreactor:
from twisted.internet import reactor
from twisted.protocols.basic import LineReceiver
from twisted.internet.protocol import ClientFactory
class ZGPClient(LineReceiver):
    """Our client object."""
    def lineReceived(self, datavar):
         "As soon as any data is received"
         print datavar

class EchoFactory(ClientFactory):
    protocol =  ZGPClient
    def startedConnecting(self, connector):
        global conn
        conn = connector
        print 'Started to connect.'

    def sendData(self, data=""):
      conn.transport.write(data.encode("ascii", "ignore") + "\n")

class main_window(wx.Frame):
 def __init__(self, parent, id, title):
  super(main_window, self).__init__(parent, id, title, style=wx.DEFAULT_FRAME_STYLE)
  self.Bind(wx.EVT_CLOSE, self.OnClose)
  self.Show(True)

 def OnClose(self, event):
   reactor.stop()
   sys.exit()

if __name__ == "__main__":
  app = wx.App()
  frame = main_window(None, wx.ID_ANY, "RS Games Client - No Game")
  reactor.registerWxApp(app)
  sockObj = EchoFactory()
  reactor.connectTCP("rsgamesmonserver.webhop.org", 3555, sockObj)
  reactor.run()
  app.MainLoop()

2 个回答

0

我在我的一个项目中也遇到过同样的问题。只需要去掉以下代码:

  1. 在 OnClose() 方法中去掉 sys.exit()。

当你使用 twisted 这个框架时,反应器(reactor)在驱动你的应用程序。如果你停止了反应器,就相当于停止了整个应用程序。问题可能是因为 sys.exit() 引发了异常(我不太确定),因为反应器会捕捉所有异常并在控制台上报告。

记住,当你使用 twisted 或其他类似的框架时,你需要换个思维方式(控制反转)。另外,我推荐你阅读这个关于 异步编程和 Twisted 的优秀教程系列。

  1. app.MainLoop()

反应器必须在它的运行方法中调用 MainLoop()。在你的代码中,你启动了两个主循环,这样你需要关闭主窗口两次才能退出。

2

这个代码可以帮到你:

def OnClose(self, evt):
    # ugly hack until wxreactor is patched:
    reactor._stopping = True
    reactor.callFromThread(_threadedselect.ThreadedSelectReactor.stop, reactor)

撰写回答