目的:實現一個可以用於接收和發送文本的TCP服務器。
思路 :
1. 兩個QLineEdit用於服務器ip和port的輸入,同時會限制ip和port的輸入。
2. 一個QPushButton,點擊后開始“監聽”,並把連接的過程放到一個線程thread中,這樣不會在等待連接的過程中造成程序阻塞。
3. 一個QlineEdit用於顯示連接后的客戶端地址和端口信息。
4. 再來一個QPushButton,關閉當前連接,如果當前連接不存在,則提示“沒有連接”。
5. 增加兩個QLineEdit用於輸入發送數據,和顯示接收數據。
1. 這里直接使用QtDesginer布局,配合GroupBox控件擺了5個QLineEdit和3個QPushButton ,保存為testGUI.ui 。
2. 用PyUIC轉化為python代碼,生成文件testGUI.py:

1 # -*- coding: utf-8 -*- 2 3 # Form implementation generated from reading ui file 'testGUi.ui' 4 # 5 # Created by: PyQt5 UI code generator 5.11.3 6 # 7 # WARNING! All changes made in this file will be lost! 8 9 from PyQt5 import QtCore, QtGui, QtWidgets 10 11 class Ui_MainWindow(object): 12 def setupUi(self, MainWindow): 13 MainWindow.setObjectName("MainWindow") 14 MainWindow.resize(547, 214) 15 sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) 16 sizePolicy.setHorizontalStretch(0) 17 sizePolicy.setVerticalStretch(0) 18 sizePolicy.setHeightForWidth(MainWindow.sizePolicy().hasHeightForWidth()) 19 MainWindow.setSizePolicy(sizePolicy) 20 self.centralwidget = QtWidgets.QWidget(MainWindow) 21 self.centralwidget.setObjectName("centralwidget") 22 self.groupBox = QtWidgets.QGroupBox(self.centralwidget) 23 self.groupBox.setGeometry(QtCore.QRect(10, 10, 331, 41)) 24 self.groupBox.setObjectName("groupBox") 25 self.listenButton = QtWidgets.QPushButton(self.groupBox) 26 self.listenButton.setGeometry(QtCore.QRect(260, 14, 61, 21)) 27 sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) 28 sizePolicy.setHorizontalStretch(1) 29 sizePolicy.setVerticalStretch(0) 30 sizePolicy.setHeightForWidth(self.listenButton.sizePolicy().hasHeightForWidth()) 31 self.listenButton.setSizePolicy(sizePolicy) 32 self.listenButton.setObjectName("listenButton") 33 self.layoutWidget = QtWidgets.QWidget(self.groupBox) 34 self.layoutWidget.setGeometry(QtCore.QRect(10, 13, 241, 22)) 35 self.layoutWidget.setObjectName("layoutWidget") 36 self.horizontalLayout = QtWidgets.QHBoxLayout(self.layoutWidget) 37 self.horizontalLayout.setContentsMargins(0, 0, 0, 0) 38 self.horizontalLayout.setObjectName("horizontalLayout") 39 self.ipLabel = QtWidgets.QLabel(self.layoutWidget) 40 self.ipLabel.setObjectName("ipLabel") 41 self.horizontalLayout.addWidget(self.ipLabel) 42 self.ipLineEdit = QtWidgets.QLineEdit(self.layoutWidget) 43 self.ipLineEdit.setObjectName("ipLineEdit") 44 self.horizontalLayout.addWidget(self.ipLineEdit) 45 self.portLabel = QtWidgets.QLabel(self.layoutWidget) 46 self.portLabel.setObjectName("portLabel") 47 self.horizontalLayout.addWidget(self.portLabel) 48 self.portLineEdit = QtWidgets.QLineEdit(self.layoutWidget) 49 self.portLineEdit.setObjectName("portLineEdit") 50 self.horizontalLayout.addWidget(self.portLineEdit) 51 self.horizontalLayout.setStretch(0, 1) 52 self.horizontalLayout.setStretch(1, 4) 53 self.horizontalLayout.setStretch(2, 1) 54 self.horizontalLayout.setStretch(3, 2) 55 self.groupBox_2 = QtWidgets.QGroupBox(self.centralwidget) 56 self.groupBox_2.setGeometry(QtCore.QRect(350, 10, 181, 41)) 57 self.groupBox_2.setObjectName("groupBox_2") 58 self.connectLineEdit = QtWidgets.QLineEdit(self.groupBox_2) 59 self.connectLineEdit.setGeometry(QtCore.QRect(10, 13, 111, 19)) 60 self.connectLineEdit.setReadOnly(True) 61 self.connectLineEdit.setObjectName("connectLineEdit") 62 self.disconnectButton = QtWidgets.QPushButton(self.groupBox_2) 63 self.disconnectButton.setGeometry(QtCore.QRect(130, 12, 41, 21)) 64 sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) 65 sizePolicy.setHorizontalStretch(1) 66 sizePolicy.setVerticalStretch(0) 67 sizePolicy.setHeightForWidth(self.disconnectButton.sizePolicy().hasHeightForWidth()) 68 self.disconnectButton.setSizePolicy(sizePolicy) 69 self.disconnectButton.setObjectName("disconnectButton") 70 self.sendLineEdit = QtWidgets.QLineEdit(self.centralwidget) 71 self.sendLineEdit.setGeometry(QtCore.QRect(60, 70, 281, 31)) 72 self.sendLineEdit.setObjectName("sendLineEdit") 73 self.sendButton = QtWidgets.QPushButton(self.centralwidget) 74 self.sendButton.setGeometry(QtCore.QRect(360, 70, 75, 31)) 75 self.sendButton.setObjectName("sendButton") 76 self.recvLineEdit = QtWidgets.QLineEdit(self.centralwidget) 77 self.recvLineEdit.setGeometry(QtCore.QRect(60, 120, 281, 31)) 78 self.recvLineEdit.setObjectName("recvLineEdit") 79 self.label = QtWidgets.QLabel(self.centralwidget) 80 self.label.setGeometry(QtCore.QRect(20, 80, 31, 16)) 81 self.label.setObjectName("label") 82 self.label_2 = QtWidgets.QLabel(self.centralwidget) 83 self.label_2.setGeometry(QtCore.QRect(20, 130, 31, 16)) 84 self.label_2.setObjectName("label_2") 85 self.groupBox_2.raise_() 86 self.groupBox.raise_() 87 self.sendLineEdit.raise_() 88 self.sendButton.raise_() 89 self.recvLineEdit.raise_() 90 self.label.raise_() 91 self.label_2.raise_() 92 MainWindow.setCentralWidget(self.centralwidget) 93 self.menubar = QtWidgets.QMenuBar(MainWindow) 94 self.menubar.setGeometry(QtCore.QRect(0, 0, 547, 23)) 95 self.menubar.setObjectName("menubar") 96 MainWindow.setMenuBar(self.menubar) 97 self.statusbar = QtWidgets.QStatusBar(MainWindow) 98 self.statusbar.setObjectName("statusbar") 99 MainWindow.setStatusBar(self.statusbar) 100 101 self.retranslateUi(MainWindow) 102 QtCore.QMetaObject.connectSlotsByName(MainWindow) 103 104 def retranslateUi(self, MainWindow): 105 _translate = QtCore.QCoreApplication.translate 106 MainWindow.setWindowTitle(_translate("MainWindow", "Test Tool")) 107 self.groupBox.setTitle(_translate("MainWindow", "網絡配置")) 108 self.listenButton.setText(_translate("MainWindow", "開始監聽")) 109 self.ipLabel.setText(_translate("MainWindow", "IP地址:")) 110 self.portLabel.setText(_translate("MainWindow", "端口:")) 111 self.groupBox_2.setTitle(_translate("MainWindow", "當前連接")) 112 self.disconnectButton.setText(_translate("MainWindow", "斷開")) 113 self.sendButton.setText(_translate("MainWindow", "發送")) 114 self.label.setText(_translate("MainWindow", "發送:")) 115 self.label_2.setText(_translate("MainWindow", "接收:"))
3. 繼承testGUI,實現主要功能:

1 import sys 2 import socket 3 import threading 4 from PyQt5.QtCore import QRegExp 5 from PyQt5.QtGui import QIntValidator,QRegExpValidator 6 from PyQt5.QtWidgets import QApplication,QMainWindow 7 from test.testGUi import Ui_MainWindow 8 9 class TestGUI(Ui_MainWindow): 10 11 def __init__(self, MainWindow): 12 """ 13 初始化界面 ,連接槽函數,以及設置校驗器 14 """ 15 self.setupUi(MainWindow) 16 self.connect_slot() 17 self.server_validator() 18 19 def start_tcp_server(self): 20 # 設置 “開始監聽” 按鈕不可用 21 self.listenButton.setDisabled(True) 22 # 實例化一個socket 23 self.sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM) 24 try: 25 ipText = self.ipLineEdit.text() 26 portValue = int(self.portLineEdit.text()) 27 self.sock.bind((ipText,portValue)) 28 except Exception as e: 29 print("請檢查ip和端口號") 30 print(e) 31 else: 32 self.sock.listen(1) 33 # 創建一個進程,用於處理socket連接和接收數據 34 server_th = threading.Thread(target=self.tcp_connect_concurrency) 35 server_th.start() 36 print("正在監聽") 37 38 # 進程函數 39 def tcp_connect_concurrency(self): 40 try: 41 connect ,address = self.sock.accept() 42 except Exception as e: 43 print(e) 44 self.base_connect = connect 45 connect_address = address[0] + ":" + str(address[1]) 46 self.connectLineEdit.setText(connect_address) 47 while True: 48 recv_msg = self.base_connect.recv(1024) 49 self.recvLineEdit.setText(recv_msg.decode('utf-8')) 50 51 def tcp_close(self): 52 """ 53 點擊'disconnect'按鈕,斷開當前連接 54 """ 55 if self.listenButton.isEnabled()==False: 56 self.listenButton.setDisabled(False) 57 try: 58 self.base_connect.close() 59 self.connectLineEdit.setText("") 60 except AttributeError as e: 61 pass 62 except Exception as e: 63 print(e) 64 65 def send_text(self): 66 """ 67 點擊“發送”發送數據/文本 68 """ 69 send_msg = self.sendLineEdit.text() 70 self.base_connect.send(send_msg.encode('utf-8')) 71 72 def server_validator(self): 73 """ 74 設置 ip 和 port 文本輸入框的限制 75 """ 76 ipValidator = QRegExpValidator(QRegExp('^((2[0-4]\d|25[0-5]|\d?\d|1\d{2})\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)$')) 77 portValidator = QIntValidator(0,65535) 78 self.ipLineEdit.setValidator(ipValidator) 79 self.portLineEdit.setValidator(portValidator) 80 self.ipLineEdit.setPlaceholderText("請輸入ip地址") 81 self.portLineEdit.setPlaceholderText("端口") 82 83 def connect_slot(self): 84 """連接各控件的槽函數""" 85 self.listenButton.clicked.connect(self.start_tcp_server) 86 self.disconnectButton.clicked.connect(self.tcp_close) 87 self.sendButton.clicked.connect(self.send_text) 88 89 if __name__ == '__main__': 90 app = QApplication(sys.argv) 91 mainWindow = QMainWindow() 92 ui = TestGUI(mainWindow) 93 mainWindow.show() 94 sys.exit(app.exec_())
4. 運行后的結果:
1)先運行mainGUI.py ,輸入如下IP地址和端口號,點擊“開始監聽”,然后運行server.py,就能獲取到連接了。
2)發送文本框輸入"你好",點擊“發送” ,client收到發送的內容,並發送文本"Hi"
3)點擊“斷開”可以斷開當前連接。