QT C++ 实现网络聊天室
一、基本原理及流程
1)知识回顾(C语言中的TCP流程)
2)QT中的服务器端/客户端的操作流程
二、代码实现
1)服务器
.ui
.pro
在pro文件中添加network库
.h
#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include <QTcpServer> //服务器头文件
#include <QTcpSocket> //客户端头文件
#include <QList> //链表头文件,用于存放客户端容器
#include <QMessageBox> //消息对话框类
#include <QDebug>QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();private slots:void on_startBtn_clicked(); //自定义启动按钮的槽函数void newConnection_slot(); //自定义处理newConnection信号的槽函数void readyRead_slot(); //自定义处理reayRead信号的槽函数private:Ui::Widget *ui;//定义服务器指针QTcpServer *server;//定义客户端指针链表容器QList<QTcpSocket *> clientList;};
#endif // WIDGET_H
.main
#include "widget.h"#include <QApplication>int main(int argc, char *argv[])
{QApplication a(argc, argv);Widget w;w.show();return a.exec();
}
.cpp
#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);//在构造函数中给服务器指针实例化对象server = new QTcpServer(this); //此时就创建一个服务器了
}Widget::~Widget()
{delete ui;
}//启动服务器按钮对应的槽函数
void Widget::on_startBtn_clicked()
{//1、获取ui界面上的端口号quint16 port = ui->portEdit->text().toUInt();//2、将服务器设置成监听状态//bool QTcpServer::listen(const QHostAddress &address = QHostAddress::Any, quint16 port = 0)//参数1:要监听的主机地址,如果是any,表示监听所有主机地址,也可以给特定的主机地址进行监听//参数2:通过指定的端口号进行访问服务器,如果是0,表示由服务器自动分配,如果非0,则表示指定端口号 (quint16 == unsignal int)//返回值:成功返回真,失败返回假if(!server->listen(QHostAddress::Any,port)){QMessageBox::critical(this,"失败","服务器启动失败"); //默认按钮为okreturn;}else{QMessageBox::information(this,"成功","服务器启动成功");}//此时表明服务器启动成功,并对客户端连接进行监听//如果有客户端向服务器发来连接请求,那么该服务器就会自动发射一个newConnection//我们可以将该信号连接到对应的槽函数中处理相关逻辑connect(server,&QTcpServer::newConnection,this,&Widget::newConnection_slot);
}//处理newConnection信号的槽函数实现
void Widget::newConnection_slot()
{qDebug()<<"有新的客户端发来连接请求了";//获取最新连接的客户端套接字//函数原型:[virtual] QTcpSocket *QTcpServer::nextPendingConnection()//参数:无//返回值:最新连接客户端套接字的指针QTcpSocket *s = server->nextPendingConnection();//将获取的套接字存放到客户端容器中clientList.push_back(s);//此时,客户端就和服务器建立起联系了//如果该套接字有数据向服务器发送过来,那么该套接字就会自动发射一个ready read信号//我们可以将该信号连接到自定义的槽函数中,然后处理相关逻辑connect(s, &QTcpSocket::readyRead, this, &Widget::readyRead_slot);
}//关于readyRead信号对应槽函数的实现
void Widget::readyRead_slot()
{//删除客户端链表中的无效客户端套接字for(int i=0;i<clientList.count();i++){//判断套接字的状态//函数原型:SocketState state() const;//功能:返回客户端套接字的状态//参数:无//返回值:客户端的状态,如果结果为0,表示未连接if(clientList[i]->state() == 0){clientList.removeAt(i); //将下标为i的客户端的套接字从链表中移除}}//遍历所有客户端,查看是哪个客户端发来数据for(int i=0 ; i<clientList.count() ; i++){//函数原型:qint64 bytesAvailable() const override;//功能:返回当前客户端套接字中的可读数据字节个数//参数:无//返回值:当前客户端待读的字节数,如果该数据为0,表示无待读数据if(clientList[i]->bytesAvailable() != 0){//读取当前客户端的相关数据,并返回一个字节数组//参数:无//返回值:数据的字节数组QByteArray msg = clientList[i]->readAll();//将数据展示到ui界面上ui->msgList->addItem(QString::fromLocal8Bit(msg));//将接收到的该消息,发送给所有客户端for(int j = 0 ; j<clientList.count() ; j++){clientList[j]->write(msg);}}}
}
2)客户端
.ui
.pro
在pro文件中添加network库
.h
#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include <QTcpSocket> //客户端头文件
#include <QMessageBox> //QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();private slots:void on_connectBtn_clicked();void connected_slot(); //自定义处理connected信号的槽函数void readyRead_slot(); //自定义处理readyRead信号的槽函数void on_sendBtn_clicked(); //自定义处理发送按钮的槽函数void disconnect_slot(); //自定义处理disconnectFromHost信号的函数void on_disConnectBtn_clicked();private:Ui::Widget *ui;//定义一个客户端指针QTcpSocket *socket;//用户名QString userName; //由于多个槽函数需要用到该用户名,所以将用户名设置为类的私有成员};
#endif // WIDGET_H
.main
#include "widget.h"#include <QApplication>int main(int argc, char *argv[])
{QApplication a(argc, argv);Widget w;w.show();return a.exec();
}
.cpp
#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);//将发送区域的组件设置为不可用状态ui->sendBtn->setEnabled(false);ui->msgEdit->setEnabled(false);ui->disConnectBtn->setEnabled(false);//给客户端指针实例化空间socket = new QTcpSocket(this);//如果连接服务器成功,该客户端就会发射一个connected的信号//我们可以将该信号连接到自定义的槽函数中处理相关逻辑//由于该连接只需要连接一次,所以,写在构造函数中即可connect(socket,&QTcpSocket::connected,this,&Widget::connected_slot);//客户端与服务器连接成功后,如果服务器向客户端发来数据,那么该客户端就会自动发送一个readyRead信号//我们只需要connect(socket,&QTcpSocket::readyRead,this,&Widget::readyRead_slot);//当客户端与服务器断开连接后,该客户端就会发射一个disconnected的信号//我们可以将该信号与自定义的槽函数连接//由于只需要连接一次,所以将该连接写到构造函数中即可//点击断开连接按钮,connect(socket,&QTcpSocket::disconnected,this,&Widget::disconnect_slot);
}Widget::~Widget()
{delete ui;
}//连接服务器按钮对应的槽函数
void Widget::on_connectBtn_clicked()
{//获取ui界面的信息userName = ui->userNameEdit->text(); //获取用户名QString hostName = ui->ipEdit->text(); //获取主机地址quint16 port = ui->portEidt->text().toUInt(); //获取端口号//调用函数连接到主机//[virtual] void QAbstractSocket::connectToHost(const QString &hostName, quint16 port)//参数1:服务器的主机地址//参数2:端口号//返回值:无socket->connectToHost(hostName,port);//如果连接服务器成功,该客户端就会发射一个connected的信号//我们可以将该信号连接到自定义的槽函数中处理相关逻辑//由于该连接只需要连接一次,所以,写在构造函数中即可
}//关于处理connected信号的槽函数的定义
void Widget::connected_slot()
{QMessageBox::information(this,"成功","连接服务器成功");//设置组件的可用状态ui->msgEdit->setEnabled(true);ui->sendBtn->setEnabled(true);ui->disConnectBtn->setEnabled(true);ui->userNameEdit->setEnabled(false);ui->ipEdit->setEnabled(false);ui->portEidt->setEnabled(false);ui->connectBtn->setEnabled(false);//顺便向服务器发送一条消息,说:***:进入聊天室QString msg = userName + ":进入聊天室";socket->write(msg.toLocal8Bit());
}//关于readyRead信号对应槽函数的实现
void Widget::readyRead_slot()
{//读取该客户端中的数据QByteArray msg = socket->readAll();//将数据展示在ui界面ui->msgList->addItem(QString::fromLocal8Bit(msg));}//发送按钮对应的槽函数
void Widget::on_sendBtn_clicked()
{//获取ui界面中的编辑的文本内容QString m = ui->msgEdit->text();//整合要发送的消息QString msg = userName + ":" + m;socket->write(msg.toLocal8Bit());//将消息编辑器中的内容清空ui->msgEdit->clear();
}//断开服务器按钮对应的槽函数
void Widget::on_disConnectBtn_clicked()
{//准备要发送的信息QString msg = userName + ":离开聊天室";socket->write(msg.toLocal8Bit());//调用成员函数disconnectFromHost//函数原型:virtual void disconnectFromHost();//功能:断开客户端与服务器的连接//参数:无socket->disconnectFromHost();//当客户端与服务器断开连接后,该客户端就会发射一个disconnected的信号//我们可以将该信号与自定义的槽函数连接//由于只需要连接一次,所以将该连接写到构造函数中即可}//关于disconnectFromHost信号对应槽函数的实现
void Widget::disconnect_slot()
{QMessageBox::information(this,"退出","断开成功");//设置组件的可用状态ui->msgEdit->setEnabled(false);ui->sendBtn->setEnabled(false);ui->disConnectBtn->setEnabled(false);ui->userNameEdit->setEnabled(true);ui->ipEdit->setEnabled(true);ui->portEidt->setEnabled(true);ui->connectBtn->setEnabled(true);
}
三、效果展示
相关文章:

QT C++ 实现网络聊天室
一、基本原理及流程 1)知识回顾(C语言中的TCP流程) 2)QT中的服务器端/客户端的操作流程 二、代码实现 1)服务器 .ui .pro 在pro文件中添加network库 .h #ifndef WIDGET_H #define WIDGET_H#include <QWidget>…...

每日一道面试题之什么是上下文切换?
上下文切换是指在计算机操作系统中,当多个进程或线程同时运行时,系统需要将当前运行进程或线程的状态(包括程序计数器、寄存器值、内存映像等)保存起来,然后切换到另一个进程或线程继续执行的过程。上下文切换通常由操…...

2023.9.3 关于 AVL 树
目录 二叉搜索树 二叉搜索树的简介: 二叉搜索树的查找: 二叉搜索树的效率: AVL树 AVL 树的简介: AVL 树的实现: AVL树的旋转 右单旋 左单旋 左右双旋 右左双旋 完整 AVL树插入代码 验证 AVL 树 AVL 树的性…...

机器学习课后习题 --- 机器学习实践
(一)单选题 1.以下关于训练集、验证集和测试集说法不正确的是( )。 A:测试集是纯粹是用于测试模型泛化能力B:训练集是用来训练以及评估模型性能 C:验证集用于调整模型参数 D:以上说法都不对 2.当数据分布不平衡时,我们可采取的措施不包括…...

git常用操作
删除分支 例:例如想删除的分支是dev_delete,那么可以按照如下的操作进行 #查看当前所在分支 git branch#如果在当前dev_delete分支上,就要切换到其他分支才能删除该分支 git checkout 其他分支#删除本地名为dev_delete的分支 git branch -d dev_delete…...

QT的补充知识
一、文件 QFile QT提供了QFile类用于对文件进行读写操作,也提供了其他的两个类:文本流(QTextSream)和数据流(QDataStream) 文本流(QTextSream):用于对文本数据的处理&am…...

【力扣周赛】第 360 场周赛(贪心 ⭐树上倍增)
文章目录 竞赛链接Q1:8015. 距离原点最远的点(贪心)Q2:8022. 找出美丽数组的最小和(贪心)Q3:2835. 使子序列的和等于目标的最少操作次数(贪心)思路竞赛时丑陋代码&#x…...

企业如何防止数据外泄——【部署智能透明加密防泄密系统】
为防止公司文件泄密,可以采取以下措施: www.drhchina.com 分部门部署:根据不同的部门需要,为不同部门用户部署灵活的加密方案。例如,对研发部、销售部、运营部的机密资料进行强制性自动加密,对普通部门的文…...

【聚类】DBCAN聚类
OPTICS是基于DBSCAN改进的一种密度聚类算法,对参数不敏感。当需要用到基于密度的聚类算法时,可以作为DBSCAN的一种替代的优化方案,以实现更优的效果。 原理 基于密度的聚类算法(1)——DBSCAN详解_dbscan聚类_root-ca…...

通过安装cpolar内网穿透在Kali上实现SSH远程连接的步骤指南
文章目录 1. 启动kali ssh 服务2. kali 安装cpolar 内网穿透3. 配置kali ssh公网地址4. 远程连接5. 固定连接SSH公网地址6. SSH固定地址连接测试 简单几步通过cpolar 内网穿透软件实现ssh 远程连接kali! 1. 启动kali ssh 服务 默认新安装的kali系统会关闭ssh 连接服务,我们通…...

UDP和TCP协议报文格式详解
在初识网络原理(初识网络原理_蜡笔小心眼子!的博客-CSDN博客)这篇博客中,我们简单的了解了一下TCP/IP五层网络模型,这篇博客将详细的学习一下五层网络模型中传输层的两个著名协议:UDP和TCP 目录 一, 传输层的作用 二, UDP 1,UDP协议的特点 2,UDP报文格式 三, TC…...

STM32+UART串口+DMA收发
目录 1、cubemax端配置 1.1 初始化配置 1.2 GPIO配置 1.3 UART配置 1.3.1 串口基础配置 1.3.2 DMA配置 2、keil端代码设计 2.1 初始化配置 2.2 DMA接收初始化配置 2.3 DMA发送配置 2.4 接收回调函数设置 2.5 回调函数内容代码编写 2.5.1 接收回调函数 2.5.2 发送回调…...

安全基础 --- js的闭包和this属性
js闭包 简介 一个函数和对其周围状态(lexical exviroment,词法环境)的引用捆绑在一起(或者说函数被引用包围),这样的组合就是闭包(closure) 在js中,通俗来讲,…...

【C语言每日一题】08. 字符三角形
题目来源:http://noi.openjudge.cn/ch0101/08 08 字符三角形 总时间限制: 1000ms 内存限制: 65536kB 问题描述 给定一个字符,用它构造一个底边长5个字符,高3个字符的等腰字符三角形。 输入 输入只有一行, 包含一个字符。 输出…...

如何打war包,并用war包更新服务器版本
1.打包,我用的maven打包 先执行clean将已经生成的包清除掉 清除完,点package进行打包 控制台输出success,证明打包成功了 文件名.war的后缀就是生成的war包 2.将war包上传致服务器 一般会在war包加上日期版本上传至服务器 解压上传的war…...

uniApp webview 中调用底座蓝牙打印功能异常
背景: 使用uniApp, 安卓底座 webView 方式开发; 调用方式采用H5 向 底座发送消息, 底座判断消息类型, 然后连接打印机进行打印; 内容通过指令集方式传递给打印机; 过程当中发现部分标签可以正常打印, 但又有部分不行,打印机没反应, 也没有报错; 原因分析: 对比标签内容…...

Mac下安装Jmeter及其配置
一、安装JDK环境 安装方式:mac下配置JDK环境_只看不学的博客-CSDN博客 如果已安装JDK环境即可忽略该步骤,检查方式,在终端输入java -version,如果出现了java版本,即代表已经配置过JDK环境了,如下图所示: …...

js+html实现打字游戏v1
实现逻辑:设置定时器每秒刷新一次,定时器刷新多少次执行一次生成单词操作来决定单词的生成速度,例如初始单词生成速度为1,那么定时器刷新5次才生成一次单词,每个单词用span来装,每组10个单词放到div里。监听…...

Java on VS Code 8月更新|反编译器用户体验优化、新 Maven 项目工作流、代码高亮稳定性提升
作者:Nick Zhu 排版:Alan Wang 大家好,欢迎来到 Visual Studio Code for Java 的 8 月更新!在这篇博客中,我们将为您提供有关反编译器支持的更多改进。此外,我们将展示如何创建没有原型的 Maven 项目以及一…...

划分Vlan时需要注意的问题
网络部分2019年才开始学习的,在学习过程中配置了整个公司的网络,心里才有了一点把握,算是掌握了最基本的。 不会的就上网学,反正网络上什么知识都有,只要有需求就对照着学,很长时间没有学习网络了ÿ…...

【广州华锐互动】利用AR远程指导系统进行机械故障排查,实现远程虚拟信息互动
随着工业自动化和智能化的不断发展,机械故障诊断已经成为了工业生产中的重要环节。为了提高故障诊断的准确性和效率,近年来,AR(增强现实)远程协助技术逐渐应用于机械故障诊断领域。本文将探讨AR远程协助技术在机械故障…...

Spring工具类--CollectionUtils的使用
原文网址:Spring工具类--CollectionUtils的使用_IT利刃出鞘的博客-CSDN博客 简介 本文介绍Spring的CollectionUtils的使用。 CollectionUtils工具类的作用:操作Collection,比如:List、Set。 判断 方法作用static boolean is…...

Node.js 应用的御用品: Node.js 错误处理系统
开发中,有些开发者会积极寻求处理错误,力求减少开发时间,但也有些人完全忽略了错误的存在。正确处理错误不仅意味着能够轻松发现和纠正错误,而且还意味着能够为大型应用程序开发出稳健的代码库。 特别是对于 Node.js 开发人员&am…...

K210-CanMV IDE开发软件
K210-CanMV IDE开发软件 界面功能简介连接设备临时运行开机运行程序 界面功能简介 区域①菜单栏:操作文件,使用工具等。 区域②快捷按钮:区域①中的文件和编辑中部分功能的快捷方式。 区域③连接设备:连接设备和程序控制按钮。 …...

0301yarnmapredude入门-hadoop-大数据学习
文章目录 1 MapReduce概述2 YARN2.1 yarn概述2.2 yarn与MapReduce关系2.3 yarn架构2.4 辅助角色 3 MapReduce & YARN部署3.1 集群规划3.2 配置文件3.3 分发配置文件 4 体验4.1 集群启动命令介绍4.2 提交MapReduce任务到YARN执行 结语 1 MapReduce概述 分布式计算是一种计算…...

大数据课程K15——Spark的TF-IDF计算Term权重
文章作者邮箱:yugongshiye@sina.cn 地址:广东惠州 ▲ 本章节目的 ⚪ 了解Spark的TF-IDF算法概念; ⚪ 了解Spark的TF-IDF算法定义; ⚪ 了解Spark的TF-IDF算法案例; 一、TF-IDF算法概述 TF-IDF(term frequency–inverse document frequency)是一种用于信…...

【C语言】字符函数,字符串函数,内存函数
大家好!今天我们来学习C语言中的字符函数,字符串函数和内存函数。 目录 1. 字符函数 1.1 字符分类函数 1.2 字符转换函数 1.2.1 tolower(将大写字母转化为小写字母) 1.2.2 toupper(将小写字母转化为大写字母&…...

Spring MVC:域对象共享数据
Spring MVC 前言域对象共享数据使用 ModelAndView 向 request 域对象中共享数据使用 Map 、Model 或 ModelMap 向 request 域对象中共享数据使用 SesionAttributes 注解向 session 域对象中共享数据使用 Servlet API 向 application 域对象中共享数据 附 前言 在上一章中&…...

Vue框架--Vue中的计算属性
下面,我们来实现一个这样的需求。 实现输入框1和输入框2中文字内容的拼接。...

面试题-React(八):React如何实现插槽?
一、React插槽的概念 插槽是一种让组件变得更加灵活和可复用的技术。它允许我们在组件内部预留一些位置,然后在组件使用时填充这些位置,实现外部内容的嵌套。 二、实现React插槽的方法 在React中,实现插槽可以通过两种方式:pro…...