嵌入式养成计划-46----QT--简易版网络聊天室实现

news2024/12/24 0:10:22

一百一十九、简易版网络聊天室实现

119.1 QT实现连接TCP协议

119.1.1 基于TCP的通信流程

在这里插入图片描述
在这里插入图片描述

119.1.2 QT中实现服务器过程

  1. 使用QTcpServer实例化一个服务器对象
  2. 设置监听状态,通过listen()函数,可以监听特定的主机,也可以监听所有客户端,端口号可以是系统自动分配的,也可以是指定端口号。
  3. 如果有客户端发来连接请求,那么服务器就自动发射一个newConnection信号,我们就可以将该信号连接到自定义的槽函数中处理该客户端的操作。
  4. 此时服务器和客户端已经建起了连接,可以调用nextPandingConnection获取最新连接的客户端套接字,可以将该套接字存放在服务器的客户端容器中。
  5. 当客户端发来数据时,该客户端就会自动发射一个readyRead信号,我们可以将该信号连接到自定义的槽函数中读取客户端数据。
  6. 通过read(),readLine(),readAll()读取套接字里的数据,可以通过write()往套接字中写入数据
  7. 关闭服务器使用close即可

119.1.3 QT中实现客户端过程

  1. 使用QTcpSocket实例化一个客户端对象
  2. 将客户端连接到服务器,使用connectToHost, 给定主机地址,端口号
  3. 如果连接成功,该客户端会自动发射connected信号,我们可以将该信号连接到自定义的槽函数中处理相关逻辑代码。
  4. 此时,客户端和服务器已经建立了连接,如果服务端发来数据,那么该客户端会自定发射readyRead信号,可以将该信号连接到自定义的槽函数中读取服务端中数据
  5. 可以使用read() readLine() readAll()读取套接字中数据,使用write往套接字中写入数据
  6. 客户端断开与服务器的连接,使用disConnectFromHost, 如果断开成功,客户端会自动发射disconnected信号,我们可以将该信号连接到自定义的槽函数中处理相关逻辑代码。

119.2 服务器端

119.2.1 UI 界面

在这里插入图片描述

119.2.2 qt_server.h

#ifndef QT_SERVER_H
#define QT_SERVER_H

#include <QWidget>
#include <QTcpServer>
#include <QList>
#include <QTcpSocket>
#include <QMessageBox>
#include <QDebug>

QT_BEGIN_NAMESPACE
namespace Ui { class Qt_Server; }
QT_END_NAMESPACE

class Qt_Server : public QWidget
{
    Q_OBJECT

public:
    Qt_Server(QWidget *parent = nullptr);
    ~Qt_Server();

private slots:
    void on_startBtn_clicked();

public slots:
    //  自定义的 处理连接的槽函数声明
    void newConnection_slot();
    //  自定义的 处理接收数据的槽函数声明
    void readyRead_slot();

private:
    Ui::Qt_Server *ui;

    QTcpServer *server;

    QList<QTcpSocket *> socketList;
};
#endif // QT_SERVER_H

119.2.3 qt_server.cpp

#include "qt_server.h"
#include "ui_qt_server.h"

Qt_Server::Qt_Server(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Qt_Server)
{
    ui->setupUi(this);

    //  给服务器指针创建空间
    server = new QTcpServer(this);
//    socketList = new QList<>();
}

Qt_Server::~Qt_Server()
{
    delete ui;
}

//  点击启动服务器按钮对应的槽函数实现
void Qt_Server::on_startBtn_clicked()
{
    if(ui->startBtn->text() == "启动服务器"){
        //  获取UI界面上输入的端口号
        quint16 port = ui->portEdit->text().toUInt();
        //  使服务器进入监听状态,返回值是bool类型
        if(server->listen(QHostAddress::Any,port)){
            QMessageBox::information(this,"提示","服务器启动成功");
        }else{
            QMessageBox::critical(this,"错误","服务器启动失败");
        }
        //  此时服务器已经进入监听状态,如果有客户端发来链接请求,
        //  则服务器会自动发射一个newConnection信号,需要将该信号连接到自定义的槽函数中处理连接的套接字
        connect(server, &QTcpServer::newConnection, this, &Qt_Server::newConnection_slot);
        ui->startBtn->setText("已启动服务器");
        ui->startBtn->setStyleSheet("background-color:green");
    }else{
        server->close();
        disconnect(server, &QTcpServer::newConnection, this, &Qt_Server::newConnection_slot);
        ui->startBtn->setStyleSheet("background-color:white");
        ui->startBtn->setText("启动服务器");
    }

}

//  自定义的 处理连接的槽函数声明
void Qt_Server::newConnection_slot()
{
    qDebug() << "有新客户的连接";
    //  获取最新连接的客户端套接字,并放入容器中,此时客户端与服务器已经建立起连接
    QTcpSocket *s = server->nextPendingConnection();
    socketList.push_back(s);

    //  如果有客户端发送数据,那么此客户端就会自动发射readyRead信号
    //  需要将该信号与自定义的处理接收数据的槽函数连接
    connect(s, &QTcpSocket::readyRead, this, &Qt_Server::readyRead_slot);
}

//  自定义的 处理接收数据的槽函数实现
void Qt_Server::readyRead_slot()
{
    //  移除无效的客户端
    //  遍历所有的客户端
    for(int i=0; i<socketList.count(); i++){
        //  判断每个客户端的状态,返回值是枚举类型
        //  socketList.at(i)->state();
        if(0 == socketList.at(i)->state()){
            //  移除当前客户端,通过下标删除
            socketList.removeAt(i);
        }
    }
    //  遍历容器,找到有需要读取数据的客户端
    for(int i=0; i<socketList.count(); i++){
        //  如果当前客户端的 有效字节数 不为0,代表当前客户端有需要读取的数据
        if(0 != socketList.at(i)->bytesAvailable()){
            //  读取客户端中的数据
            QByteArray msg = socketList.at(i)->readAll();
            //  将读取的数据放到UI界面上
            ui->listWidget->addItem(QString::fromLocal8Bit(msg));

            //  将数据发送给所有客户端
            for (int j=0; j<socketList.count(); j++) {
                socketList.at(i)->write(msg);
            }
        }
    }
}

119.2.4 main.cpp

#include "qt_server.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Qt_Server w;
    w.show();
    return a.exec();
}

119.3 客户端

119.3.1 UI 界面

在这里插入图片描述

119.3.2 qt_client.h

#ifndef QT_CLIENT_H
#define QT_CLIENT_H

#include <QWidget>
#include <QTcpServer>
#include <QList>
#include <QTcpSocket>
#include <QMessageBox>
#include <QDebug>

QT_BEGIN_NAMESPACE
namespace Ui { class Qt_Client; }
QT_END_NAMESPACE

class Qt_Client : public QWidget
{
    Q_OBJECT

public:
    Qt_Client(QWidget *parent = nullptr);
    ~Qt_Client();

public slots:
    void connected_slot();
    void readyRead_slot();

private slots:
    void on_connectBtn_clicked();

    void on_msgBtn_clicked();

    void on_disconnectBtn_clicked();

private:
    Ui::Qt_Client *ui;

    //  定一个客户端对象
    QTcpSocket *socket;
    //  定义一个用户名变量
    QString uname;
};
#endif // QT_CLIENT_H

119.3.3 qt_client.cpp

#include "qt_client.h"
#include "ui_qt_client.h"

Qt_Client::Qt_Client(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Qt_Client)
{
    ui->setupUi(this);
    //  给客户端对象创建空间
    socket = new QTcpSocket(this);

    //  初始化UI界面的组件状态
    ui->msgEdit->setEnabled(false);
    ui->msgBtn->setEnabled(false);
    ui->disconnectBtn->setEnabled(false);

}

Qt_Client::~Qt_Client()
{
    delete ui;
}

void Qt_Client::connected_slot()
{
    //  告诉服务器我进来了
    QString msg = uname + " 来了,快接驾";
    //  将这个消息发送给服务器
    socket->write(msg.toLocal8Bit());
    //  此时说明服务器与客户端已经建立连接

    //  现在将UI界面的组件状态修改一下
    ui->msgEdit->setEnabled(true);
    ui->msgBtn->setEnabled(true);
    ui->disconnectBtn->setEnabled(true);
    ui->unameEdit->setEnabled(false);
    ui->ipEdit->setEnabled(false);
    ui->portEdit->setEnabled(false);
    ui->connectBtn->setEnabled(false);

    //  如果服务器发来数据,客户端会自动发射readyRead信号
    //  因此需要将readyRead信号连接到自定义的槽函数
    //  因为只需要连接一次,所以也是该在构造函数中写连接函数
    connect(socket, &QTcpSocket::readyRead, this, &Qt_Client::readyRead_slot);
}

void Qt_Client::readyRead_slot()
{
    //  走到了这一步,说明服务器给客户端发送了消息,现在需要进行读取
    QByteArray msg = socket->readAll();
    //  将这个数据放到UI界面的消息显示框中
    ui->listWidget->addItem(QString::fromLocal8Bit(msg));
}

//  连接服务器按钮 对应的槽函数
void Qt_Client::on_connectBtn_clicked()
{
    //  获取UI界面的IP和PORT,还有uname
    QString ip = ui->ipEdit->text();
    quint16 port = ui->portEdit->text().toUInt();
    uname = ui->unameEdit->text();
    //  使客户端连接服务器
    socket->connectToHost(ip, port);

    //  判断客户端是否成功连接服务器,成功则客户端会自动发射connected信号
    //  将该信号连接到自定义的槽函数中
    //  因为只需要连接一次,所以连接函数应该写在构造函数中
    connect(socket, &QTcpSocket::connected, this, &Qt_Client::connected_slot);
}

void Qt_Client::on_msgBtn_clicked()
{
    //  获取UI界面上输入的内容
    QString msg = uname + " : " + ui->msgEdit->toPlainText();
    //  将消息发送给服务器
    socket->write(msg.toLocal8Bit());

}

void Qt_Client::on_disconnectBtn_clicked()
{
    QString msg = uname + " 走咯,我还会再回来的";
    //  将消息发送给服务器
    socket->write(msg.toLocal8Bit());
    //  断开链接
    socket->close();
    disconnect(socket, &QTcpSocket::readyRead, this, &Qt_Client::readyRead_slot);
    disconnect(socket, &QTcpSocket::connected, this, &Qt_Client::connected_slot);

    //  更改UI界面的组件状态
    ui->msgEdit->setEnabled(false);
    ui->msgBtn->setEnabled(false);
    ui->disconnectBtn->setEnabled(false);
    ui->unameEdit->setEnabled(true);
    ui->ipEdit->setEnabled(true);
    ui->portEdit->setEnabled(true);
    ui->connectBtn->setEnabled(true);
}

119.3.4 main.cpp

#include "qt_client.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Qt_Client w;
    w.show();
    return a.exec();
}

119.3.1 UI 界面

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

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

相关文章

二维码智慧门牌管理系统升级解决方案:高效、便捷、安全的外业数据管理方法

文章目录 前言一、背景与需求二、升级解决方案三、方案优势 前言 在当今的信息化社会&#xff0c;数据管理的重要性日益凸显。尤其对于像二维码智慧门牌管理系统这样的复杂系统&#xff0c;如何实现高效、便捷、安全的数据管理&#xff0c;成为了系统升级的重要议题。本文将详…

计算机数据库中了malloxx勒索病毒怎么解决,勒索病毒解密,数据恢复

随着网络技术的不断发展&#xff0c;越来越多的网络安全威胁也不断增加&#xff0c;最近&#xff0c;云天数据恢复中心接到一些企业的求助&#xff0c;企业的计算机数据库遭到了malloxx勒索病毒攻击&#xff0c;导致企业所有计算机服务器无法正常使用&#xff0c;针对此次勒索病…

51单片机定时器和中断(03)

eg1&#xff1a;数码管如何显示出字符 51单片机40个引脚的功能需要记住** RXD&#xff1a;表示的是串行输入口INT0&#xff1a;外部中断0INT1&#xff1a;外部中断1TO : 外部中断0T1 &#xff1a;外部中断1WR: 外部输入存储器写RD: 外部输出存储器读XTK2/XTL1 单片机晶振的输…

微信公众号迁移详细步骤

公众号迁移有什么作用&#xff1f;只能变更主体吗&#xff1f;很多小伙伴想做公众号迁移&#xff0c;但是不知道公众号迁移有什么作用&#xff0c;今天跟大家具体讲解一下。首先公众号迁移最主要的就是修改公众号的主体了&#xff0c;比如我们公众号原来是A公司的&#xff0c;现…

Ubuntu 22.04 中安装 fcitx5

Ubuntu 22.04 中安装 fcitx5 可以按照以下步骤进行&#xff1a; 添加 fcitx5 的 PPA 首先&#xff0c;添加 fcitx5 的官方 PPA&#xff1a; sudo add-apt-repository ppa:fcitx-team/fcitx5更新软件包列表 sudo apt update安装 fcitx5 sudo apt install fcitx5 fcitx5-conf…

基于SSM的文化培训学校网站的设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;Vue 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#xff1a;是 目录…

030-第三代软件开发-密码输入框

第三代软件开发-密码输入框 文章目录 第三代软件开发-密码输入框项目介绍密码输入框总结一下 关键字&#xff1a; Qt、 Qml、 echoMode、 TextInput、 Image 项目介绍 欢迎来到我们的 QML & C 项目&#xff01;这个项目结合了 QML&#xff08;Qt Meta-Object Language…

【Qt控件之QMdiArea】介绍及使用

描述 QMdiArea小部件提供了一个区域&#xff0c;用于显示MDI窗口。QMdiArea的功能类似于MDI窗口的窗口管理器。例如&#xff0c;它在自身上绘制和排列管理的窗口&#xff0c;可以按级联或平铺模式排列它们。通常&#xff0c;QMdiArea被用作QMainWindow的中心小部件&#xff0c…

YOLOv5算法改进(17)— 手把手教你去更换损失函数(IoU/GIoU/DIoU/CIoU/EIoU/AlphaIoU/SIoU)

前言:Hello大家好,我是小哥谈。损失函数(loss function)是机器学习中用来衡量模型预测值与真实值之间差异的函数。它用于度量模型在训练过程中的性能,以便优化模型参数。在训练过程中,损失函数会根据模型的预测结果和真实标签计算出一个标量值,代表了模型预测的错误程度…

离散低通滤波方法

低通滤波器允许低频信号通过&#xff0c;并抑制高频信号。其核心思想是在频率域上通过移除高频成分来平滑信号。这在去噪、平滑和提取基本频率成分时非常有用。 离散低通滤波方法通常采用一阶低通滤波器进行处理。一阶低通滤波器是一种常见的数字滤波器&#xff0c;能够将信号…

分享 | 对 电商API 平台的再思考

API 是推动现代企业数字化转型的基础。它不但连接了内部应用程序、合作伙伴和客户&#xff0c;同时也快速持续地向市场提供了各种新产品、版本和功能。 但当下还是以集中式的 API 交付为主。一个企业的对外 API 交付过程通常都是冗余而繁琐的&#xff0c;对企业内部的敏捷性、速…

数据丢失恢复怎么操作好?五种方法帮您恢复数据

丢失文件可能会造成灾难性的后果&#xff0c;因此您绝对需要最好的 PC 恢复软件。数据恢复软件必须快速、可靠并涵盖大多数文件格式。我们列表中最好的工具是一个甚至可以检索隐藏文件的解决方案。我们选择的另一个解决方案能够恢复700 多种独特的文件格式。 这种噩梦可能发生…

通过WinSCP实现Windows给Ubuntu(Linux)虚拟机传输数据

要实现传输有几个准备工作需要做 1.在虚拟机运行工具&#xff08;VMware或者其他&#xff09;中设置网络&#xff08;或者网络适配器&#xff09;为桥接模式&#xff08;之前是NAT模式&#xff09; 2.使用ifconfig命令查看虚拟机的网络地址 3.确定虚拟机中安装了ssh 安装 sudo…

数组问题答疑

在对数组有一定了解后我们会遇到一些问题&#xff0c;本文章将尽可能的讲解一些常见错误。 文章目录 1.数组名&#xff0c;&数组名分别代表什么&#xff1f;2.数组形式做形参时是传的整个数组还是首元素地址&#xff1f;3.为什么在主函数中用sizeof(arr)计算出的结果是整个…

登上抖音热搜榜:如何让你的内容火爆全网

在当今信息爆炸的时代&#xff0c;抖音已经成为了很多人获取信息、娱乐和社交的重要平台。每一天&#xff0c;都有大量的短视频在抖音上诞生&#xff0c;然而&#xff0c;只有少数幸运儿能够登上抖音热搜榜&#xff0c;成为万人瞩目的焦点。那么&#xff0c;如何让你的内容火爆…

【设计模式】解释器模式

文章目录 1.解释器模式定义2.解释器模式的角色3.解释器模式实战案例3.1.场景说明3.2.结构类图3.3.代码实现 4.解释器模式优缺点5.解释器模式适用场景6.解释器模式总结 主页传送门&#xff1a;&#x1f481; 传送 1.解释器模式定义 解析器模式&#xff08;Interpreter Pattern&a…

我国跨境电商行业研究报告(2022)

我国跨境电商行业研究报告 我国跨境电商规模突飞猛进&#xff0c;2022年进出口规模超2万亿元&#xff0c;2023年上半年跨境电商出口8210亿元&#xff0c;增长19.9%。全国跨境电商主体已超10万家&#xff0c;近年来涌现出一批上市公司&#xff0c;以及广州希音等全球独角兽企业。…

Java后端模拟面试 题集④

1.你先作个自我介绍吧 面试官您好&#xff0c;我叫张睿超&#xff0c;来自湖南长沙&#xff0c;大学毕业于湖南农业大学&#xff0c;是一名智能科学与技术专业的统招一本本科生。今天主要过来面试贵公司的Java后端开发工程师岗位。 大学里面主修的课程是Java、Python、数字图…

AD20 ~PCB封装库的制作

1、打开“51单片机最小系统”的工程文件。 2、创建PCB库文件&#xff1a;单击“文件”菜单&#xff0c;选择“新的”选项中的“库”选项&#xff0c;再选择“PCB 元件库”&#xff0c;进入元件PCB封装的编辑界面。 3、保存PCB库文件&#xff1a;选择“文件”菜单&#xff0c;选…

OpenCV实战——使用YOLO进行目标检测

OpenCV实战——使用YOLO进行目标检测 0. 前言1. YOLO 模型简介2. 基于 YOLO 实现目标检测3. 完整代码相关链接 0. 前言 在本节中&#xff0c;我们将使用 YOLO 算法执行目标检测。目标检测是计算机视觉中的一项常见任务&#xff0c;借助深度学习技术&#xff0c;我们可以实现高…