python套接字(三):结合pyside2实现多人聊天室

文章目录

  • 前言
  • 一、准备
    • 1、安装pyside2
    • 2、设计界面
  • 二、代码实现
    • 1、服务器端
    • 2、客户端
  • 三、运行

前言

上一章python套接字(二):实现一个服务器和多客户端连接,大概实现了多人聊天室功能,但是比较简陋,本篇内容将结合pyside2做一个有界面的多人聊天室。

一、准备

1、安装pyside2

直接命令安装就好了

pip install pyside2

2、设计界面

使用pyside2自带的designer.exe来设计界面,界面如下,界面设计具体可以参考qtdesigner页面布局,界面如下(不想设计界面也可以直接复制下面的py代码):
python套接字(三):结合pyside2实现多人聊天室_第1张图片
保存之后会得到ui文件,使用命令可以将ui文件转换成py文件:

pyside2-uic chat_win.ui > chat_win.py

能得到如下的py文件
chat_win.py

# -*- coding: utf-8 -*-

################################################################################
## Form generated from reading UI file 'chat_win.ui'
##
## Created by: Qt User Interface Compiler version 5.15.2
##
## WARNING! All changes made in this file will be lost when recompiling UI file!
################################################################################

from PySide2.QtCore import *
from PySide2.QtGui import *
from PySide2.QtWidgets import *


class Ui_ChatWin(object):
    def setupUi(self, ChatWin):
        if not ChatWin.objectName():
            ChatWin.setObjectName(u"ChatWin")
        ChatWin.resize(480, 600)
        self.verticalLayout = QVBoxLayout(ChatWin)
        self.verticalLayout.setObjectName(u"verticalLayout")
        self.horizontalLayout = QHBoxLayout()
        self.horizontalLayout.setObjectName(u"horizontalLayout")
        self.ip_label = QLabel(ChatWin)
        self.ip_label.setObjectName(u"ip_label")

        self.horizontalLayout.addWidget(self.ip_label)

        self.ip_edt = QLineEdit(ChatWin)
        self.ip_edt.setObjectName(u"ip_edt")

        self.horizontalLayout.addWidget(self.ip_edt)

        self.port_label = QLabel(ChatWin)
        self.port_label.setObjectName(u"port_label")

        self.horizontalLayout.addWidget(self.port_label)

        self.port_edt = QLineEdit(ChatWin)
        self.port_edt.setObjectName(u"port_edt")

        self.horizontalLayout.addWidget(self.port_edt)


        self.verticalLayout.addLayout(self.horizontalLayout)

        self.horizontalLayout_3 = QHBoxLayout()
        self.horizontalLayout_3.setObjectName(u"horizontalLayout_3")
        self.name_label = QLabel(ChatWin)
        self.name_label.setObjectName(u"name_label")

        self.horizontalLayout_3.addWidget(self.name_label)

        self.name_edt = QLineEdit(ChatWin)
        self.name_edt.setObjectName(u"name_edt")

        self.horizontalLayout_3.addWidget(self.name_edt)

        self.join_btn = QPushButton(ChatWin)
        self.join_btn.setObjectName(u"join_btn")

        self.horizontalLayout_3.addWidget(self.join_btn)

        self.leave_btn = QPushButton(ChatWin)
        self.leave_btn.setObjectName(u"leave_btn")

        self.horizontalLayout_3.addWidget(self.leave_btn)


        self.verticalLayout.addLayout(self.horizontalLayout_3)

        self.chat_edt = QTextEdit(ChatWin)
        self.chat_edt.setObjectName(u"chat_edt")
        self.chat_edt.setReadOnly(True)

        self.verticalLayout.addWidget(self.chat_edt)

        self.horizontalLayout_2 = QHBoxLayout()
        self.horizontalLayout_2.setObjectName(u"horizontalLayout_2")
        self.send_edt = QTextEdit(ChatWin)
        self.send_edt.setObjectName(u"send_edt")

        self.horizontalLayout_2.addWidget(self.send_edt)

        self.send_btn = QPushButton(ChatWin)
        self.send_btn.setObjectName(u"send_btn")
        sizePolicy = QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.send_btn.sizePolicy().hasHeightForWidth())
        self.send_btn.setSizePolicy(sizePolicy)

        self.horizontalLayout_2.addWidget(self.send_btn)


        self.verticalLayout.addLayout(self.horizontalLayout_2)

        self.verticalLayout.setStretch(0, 1)
        self.verticalLayout.setStretch(1, 1)
        self.verticalLayout.setStretch(2, 15)
        self.verticalLayout.setStretch(3, 3)

        self.retranslateUi(ChatWin)

        QMetaObject.connectSlotsByName(ChatWin)
    # setupUi

    def retranslateUi(self, ChatWin):
        ChatWin.setWindowTitle(QCoreApplication.translate("ChatWin", u"\u674e\u5927\u5e1d\u7684\u804a\u5929\u5ba4", None))
        self.ip_label.setText(QCoreApplication.translate("ChatWin", u"\u804a\u5929\u5ba4\u5730\u5740\uff1a", None))
        self.port_label.setText(QCoreApplication.translate("ChatWin", u"\u7aef\u53e3\uff1a", None))
        self.name_label.setText(QCoreApplication.translate("ChatWin", u"\u7528\u6237\u540d\uff1a", None))
        self.join_btn.setText(QCoreApplication.translate("ChatWin", u"\u52a0\u5165\u804a\u5929\u5ba4", None))
        self.leave_btn.setText(QCoreApplication.translate("ChatWin", u"\u79bb\u5f00\u804a\u5929\u5ba4", None))
        self.send_btn.setText(QCoreApplication.translate("ChatWin", u"\u53d1\u9001", None))
    # retranslateUi

二、代码实现

目录结构如下,主要是这三个文件,放在同一个目录下
python套接字(三):结合pyside2实现多人聊天室_第2张图片

1、服务器端

因为图形化界面是给客户用的,所以要修改的地方是客户端,服务器端不用改。

2、客户端

首先客户端需要引入图形界面的代码。发送数据因为是点击发送按钮,才发送数据,所以不用使用子线程处理,改为点击按钮触发。接收数据仍要需要一直等待服务器发送数据,所以还是需要创建一个子线程处理接收数据方法,将接收到的数据在文本框中展示。代码如下:
main.py

from PySide2.QtWidgets import QApplication, QWidget, QMessageBox
import sys
import socket
from threading import Thread
from chat_win import Ui_ChatWin


class ChatMainWin(QWidget, Ui_ChatWin):

    def __init__(self):
        self.server_addr = None         # 存放服务器地址
        self.tcp_cli_socket = None      # 创建socket对象
        super().__init__()              # 执行父类构造器
        self.setupUi(self)              # 执行Ui_ChatWin中的setupUi()方法,用于窗口展示

        self.btn_controller()           # 执行按钮绑定事件

    # 存放按钮绑定事件
    def btn_controller(self):
        self.join_btn.clicked.connect(self.join_chat)       # 加入聊天室
        self.send_btn.clicked.connect(self.msg_send)        # 发送消息
        self.leave_btn.clicked.connect(self.leave_chat)     # 离开聊天室

    def join_chat(self):
        """
        加入聊天室:
            没有和服务器连接的才能加入聊天室
        """
        if self.tcp_cli_socket is None:
            self.tcp_cli_socket = socket.socket()  # 创建socket对象
            # 获取数据
            ip = self.ip_edt.text().strip()         # 服务器ip地址
            port = self.port_edt.text().strip()     # 端口地址
            username = self.name_edt.text().strip()   # 用户名

            # 判断必要信息是否填写全
            if ip == "":
                QMessageBox.warning(self, '警告', "请输入服务器地址!")
                return

            if port == "":
                QMessageBox.warning(self, '警告', "请输入服务器端口号!")
                return

            if username == "":
                QMessageBox.warning(self, '警告', "请输入用户名!")
                return

            self.server_addr = (ip, int(port))

            # 链接服务器
            try:
                self.tcp_cli_socket.connect(self.server_addr)
            except Exception as e:
                QMessageBox.critical(self, '错误', "连接失败,请重试!")
                self.tcp_cli_socket.close()
                print(e)
                return

            self.tcp_cli_socket.send((username + ' -n').encode('utf-8'))
            data = self.tcp_cli_socket.recv(128).decode('utf-8')
            if data == "OK":
                QMessageBox.information(self, '成功', "你已成功进入聊天室!")
                # print(data)
            else:
                QMessageBox.critical(self, '失败', "进入聊天室失败,请重新尝试!")
                print(data)
                return

            t = Thread(target=self.msg_recv, daemon=True)
            t.start()

        else:
            QMessageBox.warning(self, '警告', "您已经在聊天室中!")

    def leave_chat(self):
        """
        离开聊天室:
            先判断有没有和服务器连接,有连接才能离开
        """
        choice = QMessageBox.question(self, '提示', '确定离开聊天室吗')
        # print(choice)
        if choice == QMessageBox.Yes:
            if self.tcp_cli_socket:
                self.tcp_cli_socket.send('exit'.encode("utf-8"))    # 发送exit指令到服务器
            else:
                QMessageBox.warning(self, '警告', '您还没加入任何聊天室!')

    def msg_recv(self):
        """
        接收数据:
            创建死循环来监听来自服务器的消息
        """
        while True:
            data = self.tcp_cli_socket.recv(1024)
            if data.decode("utf-8") == "exit":
                self.chat_edt.insertPlainText('您已退出聊天室\n')  # 往聊天栏里面添加数据
                break
            self.chat_edt.insertPlainText(data.decode("utf-8") + '\n')      # 往聊天栏里面添加数据

        self.tcp_cli_socket.close()
        self.tcp_cli_socket = None      # 重置值

    def msg_send(self):
        """
        发送数据
        """
        data_info = self.send_edt.toPlainText().strip()
        self.tcp_cli_socket.send((data_info + ' -ta').encode("utf-8"))
        self.send_edt.setPlainText("")      # 清空输入框内容


if __name__ == '__main__':
    app = QApplication(sys.argv)
    chat_win = ChatMainWin()
    chat_win.show()
    sys.exit(app.exec_())

三、运行

先运行服务器
在这里插入图片描述
然后运行三个服务端(main.py运行了三次),这里我讲服务器ip改成了本机的局域网ip,这样只要在一个局域网内,都可以进行通信。
python套接字(三):结合pyside2实现多人聊天室_第3张图片
大功告成,确实是可以互相通信。
最后,附上代码链接:
链接:https://pan.baidu.com/s/1IO7juzqytyhuECacRqlmMA?pwd=73j8
提取码:73j8

你可能感兴趣的:(python,socket,pyside2)