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:

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

View Code

3. 继承testGUI,实现主要功能:

1 1 import sys 2 2 import socket 3 3 import threading 4 4 from PyQt5.QtCore import QRegExp 5 5 from PyQt5.QtGui import QIntValidator,QRegExpValidator 6 6 from PyQt5.QtWidgets import QApplication,QMainWindow 7 7 from test.testGUi import Ui_MainWindow 8 8 9 9 class TestGUI(Ui_MainWindow): 1010 1111 def __init__(self, MainWindow): 1212 """ 1313 初始化界面 ,连接槽函数,以及设置校验器 1414 """ 1515 self.setupUi(MainWindow) 1616 self.connect_slot() 1717 self.server_validator() 1818 1919 def start_tcp_server(self): 2020 # 设置 “开始监听” 按钮不可用 2121 self.listenButton.setDisabled(True) 2222 # 实例化一个socket 2323 self.sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM) 2424 try: 2525 ipText = self.ipLineEdit.text() 2626 portValue = int(self.portLineEdit.text()) 2727 self.sock.bind((ipText,portValue)) 2828 except Exception as e: 2929 print("请检查ip和端口号") 3030 print(e) 3131 else: 3232 self.sock.listen(1) 3333 # 创建一个进程,用于处理socket连接和接收数据 3434 server_th = threading.Thread(target=self.tcp_connect_concurrency) 3535 server_th.start() 3636 print("正在监听") 3737 3838 # 进程函数 3939 def tcp_connect_concurrency(self): 4040 try: 4141 connect ,address = self.sock.accept() 4242 except Exception as e: 4343 print(e) 4444 self.base_connect = connect 4545 connect_address = address[0] + ":" + str(address[1]) 4646 self.connectLineEdit.setText(connect_address) 4747 while True: 4848 recv_msg = self.base_connect.recv(1024) 4949 self.recvLineEdit.setText(recv_msg.decode('utf-8')) 5050 5151 def tcp_close(self): 5252 """ 5353 点击'disconnect'按钮,断开当前连接 5454 """ 5555 if self.listenButton.isEnabled()==False: 5656 self.listenButton.setDisabled(False) 5757 try: 5858 self.base_connect.close() 5959 self.connectLineEdit.setText("") 6060 except AttributeError as e: 6161 pass 6262 except Exception as e: 6363 print(e) 6464 6565 def send_text(self): 6666 """ 6767 点击“发送”发送数据/文本 6868 """ 6969 send_msg = self.sendLineEdit.text() 7070 self.base_connect.send(send_msg.encode('utf-8')) 7171 7272 def server_validator(self): 7373 """ 7474 设置 ip 和 port 文本输入框的限制 7575 """ 7676 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?)$')) 7777 portValidator = QIntValidator(0,65535) 7878 self.ipLineEdit.setValidator(ipValidator) 7979 self.portLineEdit.setValidator(portValidator) 8080 self.ipLineEdit.setPlaceholderText("请输入ip地址") 8181 self.portLineEdit.setPlaceholderText("端口") 8282 8383 def connect_slot(self): 8484 """连接各控件的槽函数""" 8585 self.listenButton.clicked.connect(self.start_tcp_server) 8686 self.disconnectButton.clicked.connect(self.tcp_close) 8787 self.sendButton.clicked.connect(self.send_text) 8888 8989 if __name__ == '__main__': 9090 app = QApplication(sys.argv) 9191 mainWindow = QMainWindow() 9292 ui = TestGUI(mainWindow) 9393 mainWindow.show() 9494 sys.exit(app.exec_())

View Code

4. 运行后的结果:

  1)先运行mainGUI.py ,输入如下IP地址和端口号,点击“开始监听”,然后运行server.py,就能获取到连接了。

        

  2)发送文本框输入"你好",点击“发送” ,client收到发送的内容,并发送文本"Hi"

        

   3)点击“断开”可以断开当前连接。

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

java将前端的json数组字符串转换为列表

记录下在前端通过ajax提交了一个json数组的字符串,在后端如何转换为列表。前端数据转化与请求varcontracts{id:'1',name:'yanggb合同1'},{id:'2',name:'yanggb合同2'},{id:'3',name:'yang

Android So动态加载 优雅实现与原理分析

背景:漫品Android客户端集成适配转换功能(基于目标识别(So库35M)和人脸识别库(5M)),导致apk体积50M左右,为优化客户端体验,决定实现So文件动态加载.!(https://oscimg.oschina.net/oscnet/00d1ff90e4b34869664fef59e3ec3fdd20b.png)点击上方“蓝字”关注我