当前位置:网站首页>GUI 应用:socket 网络聊天室
GUI 应用:socket 网络聊天室
2022-07-04 03:53:00 【Python 集中营】
在这个周末刚刚写出来的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 threading1-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关键字抛出异常
边栏推荐
猜你喜欢

R语言中如何查看已安装的R包

Graduation project

【愚公系列】2022年7月 Go教学课程 001-Go语言前提简介

How to view installed r packages in R language

A beautiful API document generation tool

Leetcode brush question: binary tree 06 (symmetric binary tree)

R语言dplyr中的Select函数变量列名

leetcode刷题:二叉树07(二叉树的最大深度)

User defined path and file name of Baidu editor in laravel admin

精品网址导航主题整站源码 wordpress模板 自适应手机端
随机推荐
戳气球和布尔运算问题(巨难)
Boutique website navigation theme whole station source code WordPress template adaptive mobile terminal
Rhcsa 06 - suid, sgid, sticky bit (to be added)
Redis: order collection Zset type data operation command
leetcode刷题:二叉树09(二叉树的最小深度)
Flink learning 7: application structure
Application scheme of Puyuan ds1000z series digital oscilloscope in communication principle experiment
网络 - VXLAN
批处理初识
虚拟商品帐号交易平台源码_支持个人二维码收款
Configuration and hot update of nocturnal simulator in hbuildx
Asynchronous development process - touch your hand and lead you to realize a promise
【微信小程序】好看的轮播图组件
Programmers' telecommuting is mixed | community essay solicitation
DP83848+网线热拔插
ROS2中CMake编译选项的设置
C语言双向链表初版
UnicodeDecodeError: ‘gbk‘ codec can‘t decode byte 0x98 in position 1093: illegal multibyte sequence
Parameterization of controls in katalon
Understand the principle of bytecode enhancement technology through the jvm-sandbox source code