运行 服务器套接字程序无法显示 ui window

Can't show ui window when running server-socket program

我用本地主机制作简单的程序服务器-客户端,我想与我的简单 ui (PyQt5) 集成。这是我的代码:

# main program
import sys
import socket
import res
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtNetwork import *
from PyQt5.QtWidgets import *
from PyQt5 import uic
from serv import Server

SERVER = socket.gethostbyname(socket.gethostname())


class MainWindow(QWidget):
    def __init__(self):
        QWidget.__init__(self)
        uic.loadUi("serv.ui", self)
        self.setGeometry(100, 50, 400, 500)
        self.setWindowFlags(Qt.FramelessWindowHint)
        self.setAttribute(Qt.WA_TranslucentBackground)
        self.sock = self.makeServer()
        self.makeConnections()
        self.ipadd.setText(f'{SERVER}')

    def makeServer(self):
        sock = Server()
        sock.start()
        sock.clientReadyToRead.connect(self.onClientReadyToRead)
        return sock

    def makeConnections(self):
        self.startButton.clicked.connect(self.onstartButtonClicked)
        self.closeButton.clicked.connect(self.close)

    def onClientReadyToRead(self, data):
        self.messagetext.appendPlainText(data)

    def onstartButtonClicked(self):
        # port = self.portOpsi.currentText()
        # port = int(port)
        # if self.server.listen(QHostAddress(SERVER), port):
        self.messagetext.appendPlainText(f"[LISTENING] Server is listening on {SERVER}\n")
        # else:
        #     QMessageBox.critical(self, "Error", Server.errorString())

    def mousePressEvent(self, QMouseEvent):
        self.oldPosition = QMouseEvent.globalPos()

    def mouseMoveEvent(self, QMouseEvent):
        delta = QPoint(QMouseEvent.globalPos() - self.oldPosition)
        self.move(self.x() + delta.x(), self.y() + delta.y())
        self.oldPosition = QMouseEvent.globalPos()


if __name__ == "__main__":
    app = QApplication(sys.argv)
    app.setStyle("fusion")
    w = MainWindow()
    w.show()
    sys.exit(app.exec_())

服务程序:

import socket
import threading
from PyQt5.QtCore import pyqtSignal, QObject

class Server(QObject):
    clientReadyToRead = pyqtSignal(str)
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.running = 0

    def handle_client(self, conn, addr):
        print(f"[NEW CONNECTION] {self.addr} connected.")
        connected = True
        while connected:
            self.msg = self.conn.recv(1024).decode('utf-8')
            self.clientReadyToRead.emit(self.msg)
            print(f"[{self.addr}] {self.msg}")
            if self.msg == " ":
                connected = False
        self.conn.close()

    def start(self):
        SERVER = socket.gethostbyname(socket.gethostname())
        self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        PORT = 5050
        self.server.bind((SERVER, PORT))
        self.server.listen()
        print(f"[LISTENING] Server is listening on {SERVER}")
        while True:
            self.conn, self.addr = self.server.accept()
            self.thread = threading.Thread(target=self.handle_client, args=(self.conn, self.addr))
            self.thread.start()
            print(f"[ACTIVE CONNECTIONS] {threading.activeCount() - 1}")

当我 运行 我的程序时,ui 未显示,但服务器已准备好连接,只是 运行 在终端 server not showing the ui.

这是我的 ui,代码: ui when running

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>Form</class>
 <widget class="QWidget" name="Form">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>450</width>
    <height>550</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>Form</string>
  </property>
  <widget class="QWidget" name="widget" native="true">
   <property name="geometry">
    <rect>
     <x>40</x>
     <y>30</y>
     <width>370</width>
     <height>480</height>
    </rect>
   </property>
   <property name="styleSheet">
    <string notr="true">QPushButton#startButton{
    background-color: rgba(0, 0, 0, 150);
    color:rgba(225,225,225,210);
    border-radius:3px;
}
QPushButton#startButton:hover{
    background-color: rgba(20,20,20,170);
}
QPushButton#startButton:pressed{
    padding-left:2px;
    padding-top:2px;
    background-color:rgba(20,20,20,170);
}
QPushButton#closeButton{
    background-color: rgba(0, 0, 0, 0);
    color:rgba(225,225,225,210);
    border-radius:3px;
}
QPushButton#closeButton:hover{
    background-color: rgba(0, 0, 0, 0);
}
QPushButton#closeButton:pressed{
    padding-left:2px;
    padding-top:2px;
    background-color: rgba(0, 0, 0, 0);
}

QComboBox#portOpsi{
    background-color: rgba(0, 0, 0, 150);
    color:rgba(225,225,225,210);
    border-radius:3px;
}

</string>
   </property>
   <widget class="QLabel" name="label_2">
    <property name="geometry">
     <rect>
      <x>40</x>
      <y>30</y>
      <width>300</width>
      <height>420</height>
     </rect>
    </property>
    <property name="styleSheet">
     <string notr="true">border-image: url(:/res/res/mountains-3840x2160.jpg);
border-radius:15px;</string>
    </property>
    <property name="text">
     <string/>
    </property>
   </widget>
   <widget class="QLabel" name="label_3">
    <property name="geometry">
     <rect>
      <x>40</x>
      <y>30</y>
      <width>300</width>
      <height>420</height>
     </rect>
    </property>
    <property name="styleSheet">
     <string notr="true">background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1, stop:0 rgba(0, 0, 0, 9), stop:0.494318 rgba(0, 0, 0, 50), stop:1 rgba(0, 0, 0, 75));
border-radius:15px;</string>
    </property>
    <property name="text">
     <string/>
    </property>
   </widget>
   <widget class="QLabel" name="label">
    <property name="geometry">
     <rect>
      <x>50</x>
      <y>60</y>
      <width>280</width>
      <height>390</height>
     </rect>
    </property>
    <property name="styleSheet">
     <string notr="true">background-color:rgba(0,0,0,100);
border-radius:15px;</string>
    </property>
    <property name="text">
     <string/>
    </property>
   </widget>
   <widget class="QLabel" name="label_4">
    <property name="geometry">
     <rect>
      <x>150</x>
      <y>80</y>
      <width>91</width>
      <height>41</height>
     </rect>
    </property>
    <property name="font">
     <font>
      <pointsize>20</pointsize>
      <weight>75</weight>
      <bold>true</bold>
     </font>
    </property>
    <property name="styleSheet">
     <string notr="true">color:rgba(255,255,255,210);</string>
    </property>
    <property name="text">
     <string>Server</string>
    </property>
   </widget>
   <widget class="QTextEdit" name="ipadd">
    <property name="geometry">
     <rect>
      <x>75</x>
      <y>140</y>
      <width>230</width>
      <height>35</height>
     </rect>
    </property>
    <property name="font">
     <font>
      <pointsize>10</pointsize>
      <weight>75</weight>
      <italic>false</italic>
      <bold>true</bold>
      <kerning>true</kerning>
     </font>
    </property>
    <property name="styleSheet">
     <string notr="true">background-color:rgba(0,0,0,0);
border:none;
border-bottom:2px solid rgba(105,118,132,255);
color:rgba(255,255,255,230);
padding-botom:7px;</string>
    </property>
    <property name="autoFormatting">
     <set>QTextEdit::AutoNone</set>
    </property>
    <property name="html">
     <string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'MS Shell Dlg 2'; font-size:10pt; font-weight:600; font-style:normal;&quot;&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8.25pt; font-weight:400;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
    </property>
    <property name="textInteractionFlags">
     <set>Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextEditable|Qt::TextEditorInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
    </property>
    <property name="placeholderText">
     <string>IP Address</string>
    </property>
   </widget>
   <widget class="QComboBox" name="portOpsi">
    <property name="geometry">
     <rect>
      <x>150</x>
      <y>180</y>
      <width>71</width>
      <height>22</height>
     </rect>
    </property>
    <property name="styleSheet">
     <string notr="true">selection-background-color:rgba(0,0,0,255);
selection-color:(255,255,255,255);</string>
    </property>
    <property name="editable">
     <bool>false</bool>
    </property>
    <item>
     <property name="text">
      <string>5050</string>
     </property>
    </item>
    <item>
     <property name="text">
      <string>8001</string>
     </property>
    </item>
   </widget>
   <widget class="QPushButton" name="startButton">
    <property name="geometry">
     <rect>
      <x>230</x>
      <y>180</y>
      <width>75</width>
      <height>22</height>
     </rect>
    </property>
    <property name="font">
     <font>
      <pointsize>10</pointsize>
      <weight>75</weight>
      <bold>true</bold>
     </font>
    </property>
    <property name="cursor">
     <cursorShape>ArrowCursor</cursorShape>
    </property>
    <property name="styleSheet">
     <string notr="true"/>
    </property>
    <property name="text">
     <string>Start</string>
    </property>
   </widget>
   <widget class="QPlainTextEdit" name="messagetext">
    <property name="geometry">
     <rect>
      <x>75</x>
      <y>210</y>
      <width>230</width>
      <height>210</height>
     </rect>
    </property>
    <property name="font">
     <font>
      <pointsize>10</pointsize>
      <weight>75</weight>
      <bold>true</bold>
     </font>
    </property>
    <property name="styleSheet">
     <string notr="true">background-color:rgba(0,0,0,0);
border:none;
border-bottom:2px solid rgba(105,118,132,255);
color:rgba(255,255,255,230);
padding-botom:7px;</string>
    </property>
   </widget>
   <widget class="QPushButton" name="closeButton">
    <property name="geometry">
     <rect>
      <x>320</x>
      <y>35</y>
      <width>16</width>
      <height>16</height>
     </rect>
    </property>
    <property name="text">
     <string/>
    </property>
    <property name="icon">
     <iconset resource="res.qrc">
      <normaloff>:/res/res/close.png</normaloff>:/res/res/close.png</iconset>
    </property>
    <property name="iconSize">
     <size>
      <width>10</width>
      <height>10</height>
     </size>
    </property>
   </widget>
  </widget>
 </widget>
 <resources>
  <include location="res.qrc"/>
 </resources>
 <connections/>
</ui>

我只想将 ui 与服务器程序集成(显示 msg 到 ui 上的 PlainText,等等)

问题是因为s​​tart方法有一个while循环而永远不会结束。您可以使用 QTcpServer 或 asyncio,而不是使用线程和套接字。在这种情况下,我将展示第二个使用 qasync(python -m pip install qasync):

的示例
import asyncio
from functools import cached_property
from pathlib import Path
import os
import socket
import sys

from PyQt5.QtCore import QObject, Qt, pyqtSignal as Signal
from PyQt5.QtWidgets import QApplication, QWidget
from PyQt5 import uic

import qasync

CURRENT_DIRECTORY = Path(__file__).resolve().parent

SERVER = socket.gethostbyname(socket.gethostname())


class Server(QObject):
    message_changed = Signal(str)

    async def start(self, address="localhost", port=5050):
        server = await asyncio.start_server(self.handle_client, address, port)
        async with server:
            await server.serve_forever()

    async def handle_client(self, reader, writer):
        connected = True
        while connected:
            message = (await reader.read(1024)).decode("utf8")
            self.message_changed.emit(message)
            if message == " ":
                connected = False
        writer.close()


class MainWindow(QWidget):
    def __init__(self):
        QWidget.__init__(self)
        uic.loadUi(os.fspath(CURRENT_DIRECTORY / "serv.ui"), self)
        self.setGeometry(100, 50, 400, 500)
        self.setWindowFlags(Qt.FramelessWindowHint)
        self.setAttribute(Qt.WA_TranslucentBackground)
        self.makeConnections()

    @cached_property
    def server(self):
        return Server()

    def makeConnections(self):
        self.startButton.clicked.connect(self.onstartButtonClicked)
        self.closeButton.clicked.connect(self.close)
        self.server.message_changed.connect(self.handle_message_changed)

    def handle_message_changed(self, data):
        self.messagetext.appendPlainText(data)

    def onstartButtonClicked(self):
        self.messagetext.appendPlainText(
            f"[LISTENING] Server is listening on {SERVER}\n"
        )
        asyncio.ensure_future(self.server.start(SERVER))


def main():
    app = QApplication(sys.argv)
    loop = qasync.QEventLoop(app)
    asyncio.set_event_loop(loop)

    w = MainWindow()
    w.show()

    with loop:
        loop.run_forever()


if __name__ == "__main__":
    main()