PyQt5综合实践—TCP服务器
目的:实现一个可以用于接收和发送文本的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:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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,实现主要功能:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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)点击“断开”可以断开当前连接。