关闭 MainWindow 后 QtUdpSocket 仍在监听端口

QtUdpSocket still listening on port after closing MainWindow

我在 QMainWindow (udpMainWindow) 中实例化了一个 QWidget (udpWidget)。我正在从另一个 QMainWindow

创建 udpMainWindow

发生了一些 ValueError 异常(我将修复)。 当我关闭 udpMainWindow 的 window 时,我无法再对端口进行绑定,直到我关闭整个程序。我知道我需要修复正在发生的异常,但是我不明白为什么在关闭 udpMainWindow 后资源 (0.0.0.0:12345) 仍在侦听。

class udpWidget(QtGui.QWidget):
    def __init__(self, parent):
        super(udpWidget, self).__init__(parent)
        self.listenSocket=QtNetwork.QtUdpSocket()
        ...

    def do_something(self)       
        self.listenSocket.bind(12345)
        ...
        #Some Exception Occurs

        self.listenSocket.close()

    def destroy(self, destroyWindow, destroySubWindows):
        self.listenSocket.close()

    def closeEvent(self, event):
        self.listenSocket.close()
        event.accept()

class udpMainWindow(QtGui.QMainWindow):
    def __init__(self, parent):
        super(udpMainWindow, self).__init__(parent)
        myUdpWidget=udpWidget(self)
        myButton.clicked.connect(myUdpWidget.do_something)

编辑 1:

这是一个功能齐全的示例。当您使用按钮开始监听 "UDP Main Window",然后使用 'X' 按钮关闭时,端口不会释放。然后,当您尝试使用 "Main Main Window" 收听时,它无法绑定,因为它仍在使用中。

重现问题的步骤:

  1. 运行 计划
  2. 在 "UDP Main Window"
  3. 上单击 "Listen to port 12345"
  4. *点击"Listen to port 12345" on "Main Main Window" *(这只是确认端口繁忙,没有必要重现问题。
  5. 点击'x'关闭"UDP Main Window"
  6. 单击 "Main Main Window" 上的 "Listen to port 12345" 现在将无法连接。

代码

from PySide import QtGui, QtCore, QtNetwork

class udpWidget(QtGui.QWidget):
    def __init__(self, parent):
        super(udpWidget, self).__init__(parent)
        self.listenSocket=QtNetwork.QUdpSocket()
        #bindResult=self.listenSocket.bind(12345)

    @QtCore.Slot()
    def start_listening(self):
        bindResult=self.listenSocket.bind(12345)
        print "binding: {}".format(bindResult)
        raise ValueError("invalid Number") #Simulate exception occuring.
        self.listenSocket.close()


    def destroy(self, destroyWindow, destroySubWindows):
        print "udpWidget.destroy called"
        self.listenSocket.close()

    def closeEvent(self, event):
        print "udpWidget.closeEvent called"
        self.listenSocket.close()
        event.accept()

class udpMainWindow(QtGui.QMainWindow):
    def __init__(self, parent):
        super(udpMainWindow, self).__init__(parent)
        self.setWindowTitle("UDP Main Window")
        self.myUdpWidget=udpWidget(self)
        btn = QtGui.QPushButton("Listen to port 12345")
        btn.clicked.connect(self.myUdpWidget.start_listening)
        self.setCentralWidget(btn)

    def closeEvent(self, event):
        print "udpMainWindow.closeEvent called"
        #self.myUdpWidget.listenSocket.close()


class mainMainWindow(QtGui.QMainWindow):
    def __init__(self, parent):
        super(mainMainWindow, self).__init__(parent)
        self.setWindowTitle("Main Main Window")
        myUdpMainWindow = udpMainWindow(self)
        myUdpMainWindow.show()
        self.listenSocket=QtNetwork.QUdpSocket()
        btn = QtGui.QPushButton("Listen to port 12345")
        btn.clicked.connect(self.connect_udp)
        self.setCentralWidget(btn)

    @QtCore.Slot()
    def connect_udp(self):
        bindResult=self.listenSocket.bind(12345)
        print "binding: {}".format(bindResult)



if __name__=="__main__":
   myApp = QtGui.QApplication([])
   myMainMainWindow = mainMainWindow(None)
   myMainMainWindow.show()
   myApp.exec_()

如果您不关闭套接字,则在您退出应用程序之前它不会关闭是正常的。关闭一个window还不行,套接字属于应用程序而不属于window(两个windows在同一个进程中)。 如果你想关闭套接字,你必须决定在哪里做。

如果你想在start_listening函数结束时关闭套接字,那么只需在可能发生异常的地方使用异常处理:

    try:
        # here is the part where exception can happen
        raise ValueError("invalid Number") #Simulate exception occuring.
    except ValueError:
        # handle error here

    self.listenSocket.close()

如果你想在 udpMainwindow 的 closeEvent 中关闭它,那么只需取消注释行

    self.myUdpWidget.listenSocket.close()

在这段代码中,windows closeEvent 在关闭时被调用:

from PySide import QtGui, QtCore, QtNetwork

class udpMainWindow(QtGui.QMainWindow):
    def __init__(self, parent):
        super(udpMainWindow, self).__init__(parent)
        self.setWindowTitle("UDP Main Window")
        self.listenSocket=QtNetwork.QUdpSocket()
        #self.myUdpWidget=udpWidget(self)
        btn = QtGui.QPushButton("Listen to port 12345")
        btn.clicked.connect(self.start_listening)
        self.setCentralWidget(btn)

    def closeEvent(self, event):
        print "udpMainWindow.closeEvent called"
        #self.listenSocket.close()

    @QtCore.Slot()
    def start_listening(self):
        bindResult=self.listenSocket.bind(12345)
        print "binding: {}".format(bindResult)
        try:
            raise ValueError("invalid Number") #Simulate exception occuring.
        except ValueError:
            # handle error here
            pass
        finally:
            self.listenSocket.close()

class mainMainWindow(QtGui.QMainWindow):
    def __init__(self, parent):
        super(mainMainWindow, self).__init__(parent)
        self.setWindowTitle("Main Main Window")
        myUdpMainWindow = udpMainWindow(self)
        myUdpMainWindow.show()
        self.listenSocket=QtNetwork.QUdpSocket()
        btn = QtGui.QPushButton("Listen to port 12345")
        btn.clicked.connect(self.connect_udp)
        self.setCentralWidget(btn)

    @QtCore.Slot()
    def connect_udp(self):
        bindResult=self.listenSocket.bind(12345)
        print "binding: {}".format(bindResult)

    def closeEvent(self, event):
        print "mainMainWindow.closeEvent called"
        #self.listenSocket.close()

if __name__=="__main__":
   myApp = QtGui.QApplication([])
   myMainMainWindow = mainMainWindow(None)
   myMainMainWindow.show()
   myApp.exec_()