基于Python socket实现简易网络聊天室

作者:Python 时间:2021-10-19 09:10:30 

在这个周末刚刚写出来的python桌面应用--网络聊天室,主要通过pyqt5作为桌面应用框架,socket作为网络编程的框架,从而实现包括客户端和服务端的网络聊天室的GUI应用,希望可以一起学习、一起进步!

应用包括服务端server_ui.py、客户端client_ui.py两个python模块实现,并且在pyqt5的使用过程中都使用QThread多线程应用以及基本的UI页面布局。开始之前通过一个动态图来观察一下socket服务端、socket客户端通信的实现效果。

基于Python socket实现简易网络聊天室

1.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. 实现效果

基于Python socket实现简易网络聊天室

2.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 socket实现简易网络聊天室

来源:https://www.cnblogs.com/lwsbc/p/16441267.html

标签:Python,socket,聊天室
0
投稿

猜你喜欢

  • 浅析facebook的信息架构

    2008-07-25 19:57:00
  • 浅谈python下tiff图像的读取和保存方法

    2021-11-23 04:10:08
  • Python使用matplotlib绘制随机漫步图

    2022-02-20 08:34:43
  • asp.net 为FCKeditor开发代码高亮插件实现代码

    2023-09-26 00:30:16
  • 详解微信小程序开发之下拉刷新 上拉加载

    2024-05-10 13:59:52
  • pytorch中的卷积和池化计算方式详解

    2021-03-31 19:26:32
  • python爬取免费代理并验证代理是否可用

    2021-12-24 20:02:48
  • 基于Python中单例模式的几种实现方式及优化详解

    2022-10-24 14:20:45
  • pyinstaller打包后,配置文件无法正常读取的解决

    2022-12-17 18:22:09
  • ubunt18.04LTS+vscode+anaconda3下的python+C++调试方法

    2023-04-01 16:46:37
  • Python字符串内置函数功能与用法总结

    2022-08-17 00:29:29
  • MySql 随机取N条数据

    2009-03-17 12:46:00
  • 关于VSCode 装好ESLint 插件 import 报黄线的问题

    2023-01-29 07:23:23
  • 详解MySQL中InnoDB的存储文件

    2024-01-13 04:58:00
  • python有几个版本

    2021-09-12 00:44:30
  • 一个完美网站的101项指标.第四部分.设计

    2008-02-29 22:22:00
  • javascript 三 级下拉选择菜单Levels对象

    2023-09-05 03:28:48
  • 网页设计经验谈

    2007-10-30 13:11:00
  • python中实现修改图像分辨率大小

    2021-05-06 06:23:22
  • Python列表对象实现原理详解

    2022-09-07 10:24:58
  • asp之家 网络编程 m.aspxhome.com