У меня есть подкласс этого класса сервера QRunnable, который сначала транслирует UDP, а затем переключается на TCP, когда клиент подключился. У класса сервера есть событие l oop, которое убивает себя, и очередь, которую нужно вытащить, а затем отправить клиенту.
Затем у меня есть простой GUI, который я хотел ввести текст, а затем отправить его через сервера, когда я нажимаю кнопку.
Но когда я закрываю GUI мой класс потока не останавливается, который я вызвал через QThreadpool, есть ли способ правильно остановить рабочий поток после того, как я закрою GUI? У меня уже есть событие l oop, но когда я его вызвал, он ничего не сделал, но когда я использую серверный класс как обычный python потоковый класс, он может закрыться должным образом. Любая помощь приветствуется, заранее спасибо!
Код сервера:
class Server(QRunnable):
def __init__(self, ip_port):
super(Server, self).__init__()
self._stop_event = threading.Event()
self.ip_port = ip_port
self.ip_addr = ""
self.sckt = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.broadcast = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
self.client_sock = None
self.q_to_send = queue.Queue()
def get_ip_addr(self):
pattern = r'inet (?:addr:)?(?!127\.0\.0\.1)((?:\d+\.){3}\d+)'
p = subprocess.Popen(['ifconfig'], stdout=subprocess.PIPE)
self.ip_addr = re.search(pattern, p.stdout.read().decode()).group(1)
print("server ip", self.ip_addr)
def set_up_tcp(self):
self.sckt.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.sckt.settimeout(0.5)
self.sckt.bind((self.ip_addr, self.ip_port))
self.sckt.listen(5)
def broadcast_udp(self):
self.broadcast.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
self.broadcast.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
self.broadcast.sendto(bytes(self.ip_addr, encoding='utf-8'), ("<broadcast>", self.ip_port))
print("UDP broadcast sent!")
def connected(self):
self.broadcast.close()
self.client_sock.setblocking(False)
def stop(self):
self._stop_event.set()
print("Stopping server thread...")
def stopped(self):
return self._stop_event.is_set()
def run(self):
self.get_ip_addr()
self.set_up_tcp()
while not self.stopped():
while True:
self.broadcast_udp()
time.sleep(1)
try:
self.client_sock, _ = self.sckt.accept()
print("\nA client has connected!")
break
except socket.timeout:
print("socket timeout")
pass
self.connected()
print("Switched to TCP")
while True:
try:
time.sleep(0.01)
if self.q_to_send.empty():
pass
else:
msg = self.q_to_send.get()
self.client_sock.send(bytes(msg, "utf8"))
print("'" + msg + "'" + " sent")
except BrokenPipeError:
print("\nClient disconnected! Now broadcasting UDP")
break
GUI код:
class Ui_MainWindow(QMainWindow):
def __init__(self):
super(Ui_MainWindow, self).__init__()
MainWindow.setObjectName("MainWindow")
MainWindow.resize(470, 319)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.sendButton = QtWidgets.QPushButton(self.centralwidget)
self.sendButton.setGeometry(QtCore.QRect(180, 200, 112, 32))
self.sendButton.setObjectName("sendButton")
self.label = QtWidgets.QLabel(self.centralwidget)
self.label.setGeometry(QtCore.QRect(140, 30, 241, 20))
self.label.setObjectName("label")
self.textEditBox = QtWidgets.QTextEdit(self.centralwidget)
self.textEditBox.setGeometry(QtCore.QRect(120, 90, 231, 71))
self.textEditBox.setObjectName("textEditBox")
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 470, 22))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
#init UI
self.initUI()
#start server
self.server = Server(10000)
self.threadpool = QThreadPool()
self.threadpool.start(self.server)
def initUI(self):
self.sendButton.clicked.connect(self.send)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.sendButton.setText(_translate("MainWindow", "Send"))
self.label.setText(_translate("MainWindow", "Enter command below to send"))
def send(self):
self.server.q_to_send.put(self.textEditBox.toPlainText())
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
MainWindow.show()
app.exec_()