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

news2024/11/17 13:52:14

文章目录

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

前言

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

一、准备

1、安装pyside2

直接命令安装就好了

pip install pyside2

2、设计界面

使用pyside2自带的designer.exe来设计界面,界面如下,界面设计具体可以参考qtdesigner页面布局,界面如下(不想设计界面也可以直接复制下面的py代码):
在这里插入图片描述
保存之后会得到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

二、代码实现

目录结构如下,主要是这三个文件,放在同一个目录下
在这里插入图片描述

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,这样只要在一个局域网内,都可以进行通信。
在这里插入图片描述
大功告成,确实是可以互相通信。
最后,附上代码链接:
链接:https://pan.baidu.com/s/1IO7juzqytyhuECacRqlmMA?pwd=73j8
提取码:73j8

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/642133.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

车间主任、班组长必读:生产车间的现场管理

与工厂车间操作层(一线员工)接触最多的基层管理者,即我们通常所说的班组长、车间主任等,他们是将企业战略规划落实到具体工作当中的终端管理者。 一线班组长的“角色” 1、责任者 对企业来说,班组长是基层的治理员&am…

MySQL高级篇第二天

文章目录 一、Mysql的体系结构概览 二、 存储引擎 三、优化SQL步骤 一、Mysql的体系结构概览 整个MySQL Server由以下组成 Connection Pool : 连接池组件 Management Services & Utilities : 管理服务和工具组件 SQL Interface : SQL接口组件 Parser : 查询分析器组件 O…

游戏测试与一般的软件测试的区别在哪里?

有很多同学进入测试行业之后,一直从事的是软件测试的工作,然后跳槽时遇到一些游戏的公司的面试,就会有点慌,我做的都是软件测试,能胜任游戏测试么? 所以,今天我们需要先来了解一下,…

科技政策 | 《深圳市加快加快推动人工智能高质量发展高水平应用行动方案(2023—2024年)》发布

原创 | 文 BFT机器人 导语 Introduction 近日,深圳市发布了《深圳市加快推动人工智能高质量发展高水平应用行动方案(2023-2024年)》旨在以更大热情拥抱创新,打造最好生态,推动人工智能高质量发展和全方位各领域高水平…

C语言-关键字

关键字就是c语言已经定义好的名字,直接可以拿过来使用,不需要再次定义 1 数据类型相关的关键字 用于定义变量或者类型 定义变量的语法结构: 类型 变量名; 拓展:变量名属于标识符,标识符(变量…

关于Axios发请求(get或post)的参数问题

版本说明: {"name": "wx_vue_3.0","version": "0.1.0","private": true,"scripts": {"serve": "vue-cli-service serve","build": "vue-cli-service build"…

K-Means聚类算法

引言 聚类算法是传统机器学习算法中比较重要的一个算法,也是工程项目当中一个比较常用的算法。 一. 分类与聚类 分类 分类其实是从特定的数据中挖掘模式,作出判断的过程。 分类学习主要过程: (1)训练数据集存在一个类…

mathtype公式右编号对齐

mathtype公式右编号对齐 1.选中文中编辑好的公式,复制 2.mathtype里的点击右编号,将上面复制的公式粘贴到新出现的框内 3.编号设置

聚类效果评估

目录 1.轮廓系数(Silhouette Coefficient) 1.1 为什么轮廓系数可以评价聚类效果的好坏? 1.2 平均轮廓系数 2. 其他聚类质量函数 2.1方差比准则(Variance Ratio Criterion, VRC) 2.2 戴维斯-博尔丁指数(Davies-Bouldin指数,DB指数) 评价聚…

linux- 定时任务清理日志

定时任务清理日志 一、查找并删除文件1.1 查找文件1.2 查找并删除 二、计划任务:2.1 创建shell脚本,并分配权限2.2 编辑shell脚本2.3 计划任务 linux是一个很能自动产生文件的系统,在实际部署运行中,发现日志文件会占用大量内存&a…

SpringBoot+Thymeleaf 后端转html,pdf HTML生成PDF SpringBoot生成PDF Java PDF生成

SpringBoot 生成PDF Thymeleaf企业级真实应用:将HTML界面数据转换为PDF输出 参考: https://blog.51cto.com/u_13146445/6190475 https://blog.csdn.net/qq_27242695/article/details/115654447 0. 需求 后端渲染pdf生成 (thymeleaf根据已有…

Android开发之数据传递的桥梁——Bundle

解释 在安卓sdk源码中,Bundle类的说明是这样的 A mapping from String keys to various Parcelable values. See Also: PersistableBundle public final class Bundle extends BaseBundle implements Cloneable, Parcelable 字符串的键到持久化值的映射。 作用 …

只用2个小时,我把公司的进销存流程全部搬到了线上!

目录 一、前言 二、线下流程的弊端 三、仅用2个小时,如何将流程搬到线上? (1)基础资料模块 (2)采购管理模块 (3)销售管理模块 (4)库存管理模块 &…

MySQL之视图,触发器与存储过程

一、视图 视图是一个虚拟表(非真实存在),其本质是【根据SQL语句获取动态的数据集,并为其命名】,用户使用时只需使用【名称】即可获取结果集,可以将该结果集当做表来使用。 使用视图我们可以把查询过程中的…

基于虚拟化的物联网沙盒操作系统

了解她的技术 先谈谈虚拟化吧! 为什么要有虚拟化?物理CPU,物理内存和存储,物理网络的硬件能力越来越丰富的情况下,为了高效、灵活的使用资源,以及在使用时的资源隔离,把硬件资源抽象成软件资源…

机器学习第一课

实现流程: 数据输入->数据基本处理->特征工程->训练->模型评估->新数据输入->预测结果 数据类型: 类型一:特征值目标值 类型二:只有特征值 一、数据基本处理 达到的标准 二、特征工程 三、机器学习&#…

Java+Swing+mysql图书管理系统

JavaSwingmysql图书管理系统 一、系统介绍二、功能展示1.管理员登陆2.图书查询3.图书入库4.借书5.还书6.图书证管理 三、系统实现1.BookManageMainFrame.java 四、其它1.其他系统实现2.获取源码 一、系统介绍 该系统实现了 用户: 书籍查询,借书,还书功能…

本地serve跑vue或者react打包后的项目

本地跑vue或者react打包后的项目 不需要本地服务器跑打包后的build文件夹(也可能是 dist文件夹)项目。 一般方案: 方案一:本地电脑运行serve服务(本文~~)方案二:vscode编辑器安装拓展【live …

KEGG注释:KEGG富集可视化柱状图

很久很久以前,看到过文章中的KEGG富集可视化结果图。是对KEGG通路进行注释的。后来在一些测序公司的宣传页上也见到过类似的图: image.png image.png 其实这个图就是多了一个KEGG通路注释,近期也有小伙伴寻求怎么做。网上很多在线工具可以完…

第二节 柱状图

文章目录 1.数据分析流程图2. 列表与数组2.1 二者区别2.2 shape() 函数2.3 生成柱状图比较2.3.1 列表生成柱状图2.3.2 数组生成柱状图2.3.3 扩展案例练习 3. 坐标值3.1 添加横纵坐标值 4. 其他优化细节4.1 屏幕属性4.2 标题属性4.3 练习案例 5. 知识点总结 1.数据分析流程图 数…