共计 7224 个字符,预计需要花费 19 分钟才能阅读完成。
在这个周末刚刚写进去的 python 桌面利用 – 网络聊天室,次要通过 pyqt5 作为桌面利用框架,socket 作为网络编程的框架,从而实现包含客户端和服务端的网络聊天室的 GUI 利用,心愿能够一起学习、一起提高!
利用包含服务端 server_ui.py、客户端 client_ui.py 两个 python 模块实现,并且在 pyqt5 的应用过程中都应用 QThread 多线程利用以及根本的 UI 页面布局。开始之前通过一个动态图来察看一下 socket 服务端、socket 客户端通信的实现成果。
【浏览全文】
- socket_ui.py 服务端
1-1. 依赖援用
在 socket 服务端的实现过程中,除了 pyqt5 相干的 UI 界面的援用外,还包含 time、threading、sys、socket 等辅助模块来一起实现 socket 服务端的桌面应用程序。
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
import sys
from QCandyUi import CandyWindow
# 导入 socket 通信模块
import socket
# 导入工夫治理模块
import time
# 导入多线程模块
import threading
1-2. 实现过程
在服务端的业务实现下面,咱们仍然是依照之前的 GUI 实现形式,采纳主线程用来实现页面布局,子线程 QThread 来实现业务逻辑的形式来进行实现的,socket 的服务端通信业务都是在子线程 ServerThread 中编写的。上面是 socket 服务端桌面利用实现的全副代码块,copy 到本人的 ide 中即可间接启动应用。
class ServerUI(QWidget):
def __init__(self):
super(ServerUI, self).__init__()
self.init_ui()
def init_ui(self):
self.setWindowTitle('socket 服务端 公众号:[Python 集中营]')
self.setWindowIcon(QIcon('hi.ico'))
self.setFixedSize(500, 300)
hbox = QHBoxLayout()
hbox_v1 = QVBoxLayout()
self.brower = QTextBrowser()
self.brower.setFont(QFont('宋体', 8))
self.brower.setReadOnly(True)
self.brower.setPlaceholderText('音讯展现区域...')
self.brower.ensureCursorVisible()
hbox_v1.addWidget(self.brower)
hbox_v2 = QVBoxLayout()
hbox_v2_f1 = QFormLayout()
self.ip_label = QLabel()
self.ip_label.setText('ip 地址')
self.ip_txt = QLineEdit()
self.ip_txt.setPlaceholderText('0.0.0.0')
self.port_label = QLabel()
self.port_label.setText('端口')
self.port_txt = QLineEdit()
self.port_txt.setPlaceholderText('4444')
self.lis_num_label = QLabel()
self.lis_num_label.setText('最大监听个数')
self.lis_num_txt = QLineEdit()
self.lis_num_txt.setPlaceholderText('10')
self.close_cli_label = QLabel()
self.close_cli_label.setText('客户端敞开指令')
self.close_cli_txt = QLineEdit()
self.close_cli_txt.setPlaceholderText('exit,客户端发送相应指令则敞开')
hbox_v2_f1.addRow(self.ip_label, self.ip_txt)
hbox_v2_f1.addRow(self.port_label, self.port_txt)
hbox_v2_f1.addRow(self.lis_num_label, self.lis_num_txt)
hbox_v2_f1.addRow(self.close_cli_label, self.close_cli_txt)
self.start_btn = QPushButton()
self.start_btn.setText('开启服务端')
self.start_btn.clicked.connect(self.start_btn_clk)
hbox_v2.addLayout(hbox_v2_f1)
hbox_v2.addWidget(self.start_btn)
hbox.addLayout(hbox_v1)
hbox.addLayout(hbox_v2)
self.thread_ = ServerThread(self)
self.thread_.message.connect(self.show_message)
self.setLayout(hbox)
def show_message(self, text):
'''
槽函数:向文本浏览器中写入内容
:param text:
:return:
'''
cursor = self.brower.textCursor()
cursor.movePosition(QTextCursor.End)
self.brower.append(text)
self.brower.setTextCursor(cursor)
self.brower.ensureCursorVisible()
def start_btn_clk(self):
self.thread_.start()
self.start_btn.setEnabled(False)
class ServerThread(QThread):
message = pyqtSignal(str)
def __init__(self, parent=None):
super(ServerThread, self).__init__(parent)
self.parent = parent
self.working = True
def __del__(self):
self.working = False
self.wait()
def run(self):
self.message.emit('筹备启动 socket 服务端...')
# 创立服务端 socket
socket_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 绑定服务地址、端口
address = (self.parent.ip_txt.text().strip(), int(self.parent.port_txt.text().strip()))
socket_server.bind(address)
# 设置监听最大期待数
socket_server.listen(int(self.parent.lis_num_txt.text().strip()))
self.message.emit("服务曾经启动,正在期待客户端连贯...")
while True:
# 设置睡眠工夫
time.sleep(0.1)
# 容许客户端连贯
client, info = socket_server.accept()
self.client, self.info = client, info
# 启用新线程调用音讯解决
thread = threading.Thread(target=self.catch_message)
# 设置为守护线程
thread.setDaemon(True)
# 开启线程执行
thread.start()
def catch_message(self):
self.client.send("欢送来到网络聊天室".encode('utf-8'))
self.message.emit("客户端信息:" + str(self.info))
close_cli = self.parent.close_cli_txt.text().strip()
while True:
try:
# 接管客户端音讯、接管最大长度为 1024,并进行 utf-8 解码
message = self.client.recv(1024).decode('utf-8')
# 校验是否敞开客户端
if not message and close_cli == message:
self.client.close()
self.message.emit("以后客户端已敞开!")
break
self.message.emit("接管到音讯:" + message)
# 将音讯进行 utf-8 编码后发给客户端
rcv = "服务端胜利接管音讯:" + message
self.client.send(rcv.encode('utf-8'))
except Exception as e:
self.client.send("服务端解决音讯异样!".encode('utf-8'))
break
if __name__ == '__main__':
app = QApplication(sys.argv)
w = CandyWindow.createWindow(ServerUI(), theme='blueGreen', title='socket 服务端 公众号:[Python 集中营]',
ico_path='hi.ico')
w.show()
sys.exit(app.exec_())
1-3. 实现成果
- client_ui.py 客户端
2-1. 依赖援用
在 socket 客户端的实现过程中,除了 pyqt5 相干的 UI 界面的援用外,还包含 sys、socket 等辅助模块来一起实现 socket 服务端的桌面应用程序,相比服务端来说,客户端并没有应用多线程 threading 模块。
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
import sys
from QCandyUi import CandyWindow
# 导入 socket 通信模块
import socket
2-2. 实现过程
客户端的实现过程和服务端 server_ui.py 实现是根本类似的,同样也应用到了 pyqt5 的 QThread 的子线程利用,惟一不同的是 socket 客户端通信形式跟服务端不大雷同,同样将上面的代码块 copy 到本人的 ide 中间接应用即可。
class ClientUI(QWidget):
def __init__(self):
super(ClientUI, self).__init__()
self.init_ui()
def init_ui(self):
self.setWindowTitle('socket 客户端 公众号:[Python 集中营]')
self.setWindowIcon(QIcon('hi.ico'))
self.setFixedSize(500, 300)
hbox = QHBoxLayout()
hbox_v1 = QVBoxLayout()
self.brower = QTextBrowser()
self.brower.setFont(QFont('宋体', 8))
self.brower.setReadOnly(True)
self.brower.setPlaceholderText('音讯展现区域...')
self.brower.ensureCursorVisible()
hbox_v1.addWidget(self.brower)
hbox_v2 = QVBoxLayout()
hbox_v2_g1 = QGridLayout()
self.ip_label = QLabel()
self.ip_label.setText('ip 地址')
self.ip_txt = QLineEdit()
self.ip_txt.setPlaceholderText('0.0.0.0')
self.port_label = QLabel()
self.port_label.setText('端口')
self.port_txt = QLineEdit()
self.port_txt.setPlaceholderText('4444')
self.message = QTextEdit()
self.message.setPlaceholderText('发送音讯内容...')
hbox_v2_g1.addWidget(self.ip_label, 0, 0, 1, 1)
hbox_v2_g1.addWidget(self.ip_txt, 0, 1, 1, 1)
hbox_v2_g1.addWidget(self.port_label, 1, 0, 1, 1)
hbox_v2_g1.addWidget(self.port_txt, 1, 1, 1, 1)
hbox_v2_g1.addWidget(self.message, 2, 0, 1, 2)
self.start_btn = QPushButton()
self.start_btn.setText('发送音讯')
self.start_btn.clicked.connect(self.start_btn_clk)
hbox_v2.addLayout(hbox_v2_g1)
hbox_v2.addWidget(self.start_btn)
hbox.addLayout(hbox_v1)
hbox.addLayout(hbox_v2)
self.thread_ = ClientThread(self)
self.thread_.message.connect(self.show_message)
self.setLayout(hbox)
def show_message(self, text):
'''
槽函数:向文本浏览器中写入内容
:param text:
:return:
'''
cursor = self.brower.textCursor()
cursor.movePosition(QTextCursor.End)
self.brower.append(text)
self.brower.setTextCursor(cursor)
self.brower.ensureCursorVisible()
def start_btn_clk(self):
self.thread_.start()
class ClientThread(QThread):
message = pyqtSignal(str)
def __init__(self, parent=None):
super(ClientThread, self).__init__(parent)
self.parent = parent
self.working = True
self.is_connect = False
def __del__(self):
self.working = False
self.wait()
def run(self):
try:
if self.is_connect is False:
self.connect_serv()
# 将控制台输出音讯进行 utf-8 编码后发送
self.socket_client.send(self.parent.message.toPlainText().strip().encode('utf-8'))
self.message.emit(self.socket_client.recv(1024).decode('utf-8'))
except Exception as e:
self.message.emit("发送音讯异样:" + str(e))
def connect_serv(self):
try:
self.message.emit("正在创立客户端 socket...")
# 创立客户端 socket
self.socket_client = socket.socket()
# 连贯服务端
address = (self.parent.ip_txt.text().strip(), int(self.parent.port_txt.text().strip()))
self.socket_client.connect(address)
self.message.emit("服务端连贯胜利...")
# 接管服务端音讯并进行 utf-8 解码
self.message.emit(self.socket_client.recv(1024).decode())
self.is_connect = True
except:
self.is_connect = False
if __name__ == '__main__':
app = QApplication(sys.argv)
w = CandyWindow.createWindow(ClientUI(), theme='blueGreen', title='socket 客户端 公众号:[Python 集中营]',
ico_path='hi.ico')
w.show()
sys.exit(app.exec_())
2-3. 实现成果
【往期精彩】
零配置 python 日志,装置即用!
英语没学好到底能不能做 coder,别再纠结了先学起来 …
数据荡涤工具 flashtext,效率间接晋升了几十倍数!
一个 help 函数解决了 python 的所有文档信息查看 …
python 自定义异样 /raise 关键字抛出异样