目的:实现一个可以用于接收和发送文本的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", "接收:"))
View Code
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_())
View Code
4. 运行后的结果:
1)先运行mainGUI.py ,输入如下IP地址和端口号,点击“开始监听”,然后运行server.py,就能获取到连接了。
2)发送文本框输入"你好",点击“发送” ,client收到发送的内容,并发送文本"Hi"
3)点击“断开”可以断开当前连接。