QT——TCP网络调试助手

目录

一.项目展示

​编辑

二.开发流程

三.QTcpServer、QTcpSocket、QUdpSocket类的学习

1.QTcpServer服务端

2.QTcpSocket客户端

3.Udp通信

四.网络调试助手

1.首先我们实现当用户选择不同协议类型时不同的UI组件如何切换

2.实现打开/关闭按键图片的切换

方式一:通过其父类所提供的void setIcon(const QIcon &icon)函数去实现

方式二:重写QPushButton的事件

3.定时发送

 4.实现代码如下


一.项目展示

二.开发流程

三.QTcpServer、QTcpSocket、QUdpSocket类的学习

Tcp面向连接的基于字节流的协议(点对点)

Udp面向无连接的基于报文的协议(一对一、一对多、多对多)

3.1QTcpServer类中包含以下函数

listen(const QHostAddress &address = QHostAddress::Any, quint16 port = 0);用于监听

QTcpSocket nextPendingConnection();                        

从监听套接字中获取一个已准备好的客户端进行连接
deleteLater();

释放资源

disconnectFromHost(); 

断开连接

 QTcpServer类包含以下信号

newConnection();监听到有新的连接时
acceptError(QAbstractSocket::SocketError socketError);尝试接受新的连接时发生错误

 3.2QTcpSocket类包含以下函数

connectToHost(const QHostAddress &address = QHostAddress::Any, quint16 port = 0);连接服务端

QHostAddress peerAddress();

获取ip地址
quint16 clientPort();获取端口号
readall();读取消息
write(QByteArray data);发送数据
state();判断当前状态,如:if(socket->state== QAbstractSocket::ConnectedState)
deleteLater();释放资源

 QTcpSocket类包含以下信号

connected();成功连接
readyRead();有新的数据发来时
disconnected();断开连接时

3.3QUdpSocket类包含以下函数

bind(const QHostAddress &address = QHostAddress::Any, quint16 port = 0);绑定ip地址和端口,接受数据时使用
bool hasPendingDatagrams() const;用于检查是否有待处理的数据报。返回 true: 表示有一个或多个待处理的数据报
pendingDatagramSize();通常用于设置接受缓冲区的大小时使用,返回下一个待处理的数据报的大小
readDatagram(buffer.data(), buffer.size(), &sender, &senderPort); 将接收到的数据存储到提供的缓冲区中
writeDatagram(<要发送的数据>, <ip地址>, <端口号>); ip为QHostAddress::Broadcast代表广播发送
close();关闭udp套接字
deleteLater();释放资源

 QUdpSocket类包含以下信号

readyRead();有新的数据发来时

3.4以下程序可获取本地ip地址

// 获取本地主机名称
QString localHostName = QHostInfo::localHostName(); // 根据本地主机名称获取本地主机信息
QHostInfo info = QHostInfo::fromName(localHostName); // 将本地主机的所有 IP 地址赋值给容器中
QList<QHostAddress> addresses = info.addresses(); // 清空 comboBox_2 并添加 IPv4 地址
ui->comboBox_2->clear(); 
for (const auto& address : addresses) {if (address.protocol() == QAbstractSocket::IPv4Protocol) {qDebug() << "IPv4 Address:" << address.toString();ui->comboBox_2->addItem(address.toString());}
}

1.QTcpServer服务端

QTcpServer* server = new QTcpServer(this);               //创建一个监听套接字
server->listen();                                        //开始监听指定ip与端口connect(server, &QTcpServer::newConnection, this, [=](){ //信号与槽连接:当监听到有新的连接时QTcpSocket* clientSocket;                            //创建一个网络套接字clientSocket = server->nextPendingConnection();      //从监听套接字中获取一个已准备好的客户端进行连接//获取客户端的ip与端口号QHostAddress clientAddress = clientSocket->peerAddress();quint16 clientPort = clientSocket->peerPort();//信号与槽连接:当有新的消息时connect(clientSocket, &QTcpSocket::readyRead, this, [=](){QByteArray data = clientSocket->readAll();       //读取消息);//信号与槽连接:当客户端断开连接时connect(clientSocket, &QTcpSocket::disconnected, this, [=](){clientPort->deleteLater();                       //释放资源);if(clientSocket->state() == QAbstractSocket::ConnectedState){cnt = clientSocket->write(arrayData);}
);server->close();                                         //关闭服务端

2.QTcpSocket客户端

QTcpSocket* socket = new QTcpSocket(this);
connect(socket, &QTcpSocket::connected, this, [=]() {       //客户端连接到服务端槽函数//...
});connect(socket, &QTcpSocket::readyRead, this, [=]() {       //客户端接收到数据槽函数int sum = 0;QByteArray data = socket->readAll();                    //读取接收到的数据sum = data.size();
}connect(socket, &QTcpSocket::disconnected, this, [=]() {    //客户端与服务端断开连接槽函数qDebug() << "Disconnected from server.";socket->deleteLater();                                  //断开连接时删除 socket
});if(socket->state() == QAbstractSocket::ConnectedState){     //客户端发送数据socket->write(arrayData);
}socket->connectToHost(remIpaddress, remPort);               //尝试连接服务端socket->disconnectFromHost();                               //主动断开与客户端的连接
socket->deleteLater();                                      //释放资源

3.Udp通信

QUdpSocke* udp = new QUdpSocket(this);                   
udp->bind(ipaddress, honts.toInt();             //接受数据时使用,绑定ip地址和端口//绑定信号与槽,当接收到数据时 
connect(udp, &QUdpSocket::readyRead, this, [=](){                                               while (udp->hasPendingDatagrams()) {        //检查是否有待处理的数据报,循环读取QByteArray buffer;buffer.resize(int(udp->pendingDatagramSize()));   //确保接收缓冲区大小合适QHostAddress sender;                    //发送者的地址quint16 senderPort;                     //发送者的端口//读取数据并存入buffer中udp->readDatagram(buffer.data(), buffer.size(), &sender, &senderPort); }
);udp->writeDatagram(<要发送的数据>, <ip地址>, <端口号>); QHostAddress broadcastAddress = QHostAddress::Broadcast;                     // 设置广播地址
qint64 bytesWritten = con->writeDatagram(arrayData, broadcastAddress, port); // 发送广播udp->close();                                      
udp->deleteLater();                                

四.网络调试助手

1.首先我们实现当用户选择不同协议类型时不同的UI组件如何切换

绑定信号&QComboBox::currentIndexChangedQComBobox组件,当QComboBox组件的索引变化时,执行下面槽函数,实现不同的UI组件之间的切换

void Widget::on_CurrentIndexChanged() {// 获取用户当前选择的索引currentIndex = ui->comboBox_1->currentIndex();// 删除垂直布局中的第六个组件(如果存在)if (ui->verticalLayout->count() >= 6) {QWidget* widget = ui->verticalLayout->itemAt(5)->widget(); // 获取第六个控件if (widget) {ui->verticalLayout->removeWidget(widget);   // 从布局中移除widget->deleteLater();                       // 删除组件}}// 根据选择的索引更新界面if (currentIndex == 1) {  // 用户选择了客户端ui->label_2->setText("(2)本地主机地址");ui->label_3->setText("(3)远程主机地址");box = new QComboBox(this);                    // 创建新的 QComboBoxbox->addItem("192.168.56.1 :8080");           // 向组件中添加内容box->setEditable(true);                        // 设置组件中的内容可修改ui->verticalLayout->addWidget(box);            // 将组件添加到垂直布局中box->show();                                   // 显示新创建的 QComboBox} else if (currentIndex == 0) {  // 用户选择了UDPui->lineEdit_rev->setText("192.168.238.1");ui->lineEdit_revHonts->setText("8080");ui->label_2->setText("(2)本地主机地址");ui->label_3->setText("(3)本地主机端口");edt = new QLineEdit(this);                     // 创建新的 QLineEditedt->setText("8080");                          // 设置新的 QLineEdit 显示的内容ui->verticalLayout->addWidget(edt);            // 将组件添加到垂直布局中edt->show();                                   // 显示新创建的 QLineEdit} else {  // 用户选择了服务端ui->label_2->setText("(2)本地主机地址");ui->label_3->setText("(3)本地主机端口");edt = new QLineEdit(this);                     // 创建新的 QLineEditedt->setText("8080");                          // 设置新的 QLineEdit 显示的内容ui->verticalLayout->addWidget(edt);            // 将组件添加到垂直布局中edt->show();                                   // 显示新创建的 QLineEdit}
}

2.实现打开/关闭按键图片的切换

方式一:通过其父类所提供的void setIcon(const QIcon &icon)函数去实现

const QString ICON_PATH_MM = ":/pictures/mm.png"; // 图标路径常量
const QString ICON_PATH_PP = ":/pictures/pp.png"; // 图标路径常量Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);ui->pushButton->setCheckable(true);// 设置按钮透明背景ui->pushButton->setStyleSheet("QPushButton {""background-color: transparent;""border: none;" // 可选:去掉按钮边框"}");// 设置图标和大小setButtonIconAndSize(ICON_PATH_MM);
}void Widget::on_pushButton_clicked(bool checked)
{// 根据按钮的 checked 状态切换图标setButtonIconAndSize(checked ? ICON_PATH_PP : ICON_PATH_MM);
}// 封装设置图标和大小的逻辑
void Widget::setButtonIconAndSize(const QString &iconPath)
{QSize buttonSize = ui->pushButton->size(); // 获取按钮的当前大小ui->pushButton->setIconSize(buttonSize);   // 设置图标大小ui->pushButton->setIcon(QIcon(iconPath));  // 设置图标
}

方式二:重写QPushButton的事件

bool t = true;myBtnOpen::myBtnOpen(QWidget *parent):QPushButton(parent)
{// 加载初始图片pic.load(":/pictures/mm.png");// 设置按钮的固定大小为图片的大小//setFixedSize(pic.size());//setFixedSize(100,100);// 刷新界面,触发 paintEvent 进行绘制update();
}void myBtnOpen::paintEvent(QPaintEvent *e)
{// 创建一个 QPainter 对象,负责绘制图片QPainter painter(this);// 使用 QPainter 在按钮区域内绘制当前加载的图片painter.drawPixmap(rect(), pic);
}void myBtnOpen::mousePressEvent(QMouseEvent *e)
{if(e->button() == Qt::LeftButton){//打开if(t == true){pic.load(":/pictures/mm.png");update();t = false;}else{pic.load(":/pictures/pp.png");update();t = true;}}QPushButton::mousePressEvent(e);
}

3.定时发送

通过定时器实现,当用户勾选定时发送组件时

1.初始化定时器,设置定时器定时时间,启动定时器。

2.在构造函数中绑定定时器的超时信号与槽函数,通过Lambda表达式调用发送函数既可以

//定时发送槽函数
void Widget::on_checkBox_10_clicked(bool checked)
{if(checked){//设置定时器定时时间timer->setInterval(ui->lineEdit_msData->text().toInt());//启动定时器timer->start();}else{//停止定时器timer->stop();}
}
//发送按键槽函数
void Widget::on_pushButton_send_clicked()
{//(1)先获取用户输入的要发送的内容QString data = ui->textEdit_sendData->toPlainText();QByteArray arrayData = data.toLocal8Bit();int cnt = 0;//(2)判断Hex发送是否勾选,此处为勾选if (ui->checkBox_9->isChecked()) {// a.检查字节数是否是偶数if (0 != arrayData.size() % 2) {ui->label_state->setText("input error!");return;}// b.检查是否符合Hex表达for (char c : arrayData) {if (!isxdigit(c)) {ui->label_state->setText("input error!");return;}}// c.转化为16进制arrayData = QByteArray::fromHex(arrayData);}//(3).开始发送if (t == 1) {        // 客户端发送数据cnt = socket->write(arrayData);} else if (t == 2) { // 服务端发送数据cnt = clientSocket->write(arrayData);}//(4)判断是否发送成功if (cnt == -1) {ui->label_state->setText("send error!");} else {if (ui->checkBox_8->isChecked()) {ui->textEdit_sendData->clear();}sendCnt += cnt;ui->label_state->setText("send OK!");ui->label_sendCnt->setText("发送: " + QString::number(sendCnt));}
}

 4.实现代码如下

tunnek/mi (github.com)

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

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

相关文章

导航栏渐变色iOS

- (void)viewDidLoad {[super viewDidLoad];// 设置导航栏属性self.navigationBar.translucent NO;[self.navigationBar setTitleTextAttributes:{NSForegroundColorAttributeName : [UIColor whiteColor], NSFontAttributeName:[UIFont boldSystemFontOfSize:28]}];// 修复iO…

《Web性能权威指南》-浏览器API与协议-读书笔记

本文是《Web性能权威指南》第四部分——浏览器API与协议的读书笔记。 第一部分——网络技术概览&#xff0c;请参考网络技术概览&#xff1b; 第二部分——无线网络性能&#xff0c;请参考无线网络性能&#xff1b; 第三部分——HTTP&#xff0c;请参考HTTP。 浏览器网络概述 …

使用TypeORM进行数据库操作

&#x1f493; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4dd; Gitee主页&#xff1a;瑕疵的gitee主页 ⏩ 文章专栏&#xff1a;《热点资讯》 使用TypeORM进行数据库操作 引言 TypeORM 简介 安装 TypeORM 配置 TypeORM 定义实体 连接数据库 运行项目 高级功能 事务管理 关…

ESP-HaloPanel:用 ESP32-C2 打造超低成本智能家居面板

项目简介 在生活品质日益提升的今天&#xff0c;智能家居系统已经走进了千家万户&#xff0c;并逐渐成为现代生活的一部份。与此同时&#xff0c;一款设计精致、体积轻盈、操作简便的全屋智能家居控制面板&#xff0c;已经成为众多家庭的新宠。这种高效、直观的智能化的解决方…

Hadoop生态圈框架部署(四)- Hadoop完全分布式部署

文章目录 前言一、Hadoop完全分布式部署&#xff08;手动部署&#xff09;1. 下载hadoop2. 上传安装包2. 解压hadoop安装包3. 配置hadoop配置文件3.1 虚拟机hadoop1修改hadoop配置文件3.1.1 修改 hadoop-env.sh 配置文件3.3.2 修改 core-site.xml 配置文件3.3.3 修改 hdfs-site…

数据建模圣经|数据模型资源手册卷3,数据建模最佳实践

简介 本书采用了类设计模式的方式对数据模型进行高度抽象总结&#xff0c;展现了常见的数据模型构建模型等模型的作用、层次、分类、地位、沟通方式&#xff0c;和业务规则。使用一个强大的数据模型模式的数据建模&#xff0c;评估特定与广义模型的优缺点&#xff0c;有助于你改…

【力扣】Go语言回溯算法详细实现与方法论提炼

文章目录 一、引言二、回溯算法的核心概念三、组合问题1. LeetCode 77. 组合2. LeetCode 216. 组合总和III3. LeetCode 17. 电话号码的字母组合4. LeetCode 39. 组合总和5. LeetCode 40. 组合总和 II小结 四、分割问题6. LeetCode 131. 分割回文串7. LeetCode 93. 复原IP地址小…

#渗透测试#SRC漏洞挖掘# 信息收集-Shodan进阶之Mongodb未授权访问

免责声明 本教程仅为合法的教学目的而准备&#xff0c;严禁用于任何形式的违法犯罪活动及其他商业行为&#xff0c;在使用本教程前&#xff0c;您应确保该行为符合当地的法律法规&#xff0c;继续阅读即表示您需自行承担所有操作的后果&#xff0c;如有异议&#xff0c;请立即停…

Golang--流程控制

1、分支结构 1.1 if分支 单分支 语法&#xff1a;if 条件表达式 { 逻辑代码 } 当条件表达式为true时&#xff0c;就会执行代码块的代码。条件表达式左右的()可以不写&#xff0c;也建议不写 if和表达式中间&#xff0c;一定要有空格在Golang中&#xff0c;{}是必须有的,就算你…

【补补漏洞吧 | 02】等保测评ZooKeeperElasticsearch未授权访问漏洞补漏方法

一、项目背景 客户新系统上线&#xff0c;因为行业网络安全要求&#xff0c;需要做等保测评&#xff0c; 通过第三方漏扫工具扫描系统&#xff0c;漏扫报告显示ZooKeeper和 Elasticsearch 服务各拥有一个漏洞&#xff0c;具体结果如下&#xff1a; 1、ZooKeeper 未授权访问【…

Serverless + AI 让应用开发更简单

本文整理自 2024 云栖大会&#xff0c;阿里云智能高级技术专家&#xff0c;史明伟演讲议题《Serverless AI 让应用开发更简单》 随着云计算和人工智能&#xff08;AI&#xff09;技术的飞速发展&#xff0c;企业对于高效、灵活且成本效益高的解决方案的需求日益增长。本文旨在…

从0开始学PHP面向对象内容之(类,对象,构造/析构函数)

上期我们讲了面向对象的一些基本信息&#xff0c;这期让我们详细的了解一下 一、面向对象—类 1、PHP类的定义语法&#xff1a; <?php class className {var $var1;var $var2 "constant string";function classfunc ($arg1, $arg2) {[..]}[..] } ?>2、解…

(八)JavaWeb后端开发——Tomcat

目录 1.Web服务器概念 2.tomcat 1.Web服务器概念 服务器&#xff1a;安装了服务器软件的计算机服务器软件&#xff1a;接收用户的请求&#xff0c;处理请求&#xff0c;做出响应web服务器软件&#xff1a;在web服务器软件中&#xff0c;可以部署web项目&#xff0c;让用户通…

【Linux系列】Linux 和 Unix 系统中的`set`命令与错误处理

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

Nuxt.js 应用中的 nitro:config 事件钩子详解

title: Nuxt.js 应用中的 nitro:config 事件钩子详解 date: 2024/11/2 updated: 2024/11/2 author: cmdragon excerpt: nitro:config 是 Nuxt 3 中的一个生命周期钩子,允许开发者在初始化 Nitro 之前自定义 Nitro 的配置。Nitro 是 Nuxt 3 的服务器引擎,负责处理请求、渲…

[论文阅读]LOGAN: Membership Inference Attacks Against Generative Models

LOGAN: Membership Inference Attacks Against Generative Models https://arxiv.org/abs/1705.07663v4 Proceedings on Privacy Enhancing Technologies &#xff08;PoPETs&#xff09;&#xff0c;第 2019 卷&#xff0c;第 1 期。 这篇文章是17年的一篇文章&#xff0c;…

使用Vite构建现代化前端应用

&#x1f493; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4dd; Gitee主页&#xff1a;瑕疵的gitee主页 ⏩ 文章专栏&#xff1a;《热点资讯》 使用Vite构建现代化前端应用 引言 Vite 简介 安装 Vite 创建项目 启动开发服务器 项目结构 配置 Vite 开发模式 生产构建 使用插…

Node.js:模块 包

Node.js&#xff1a;模块 & 包 模块module对象 包npm安装包配置文件镜像源 分类 模块 模块化是指解决一个复杂问题时&#xff0c;自顶向下逐层把系统划分成若干模块的过程。对于整个系统来说&#xff0c;模块是可组合、分解和更换的单元。 简单来说&#xff0c;就是把一个…

【Arduino】一分钟快速在vs code 编译开发Arduino

下载Arduino 对于一些开发者来说&#xff0c;Arduino开发较为不方便&#xff0c;不管从代码的阅读性、开发效率等等方面&#xff0c;vs code都要优于Arduino IDE开发&#xff0c;而且vs code开发可以使用插件&#xff0c;比如一些AI代码插件&#xff0c;可以加快开发速率&#…

WPF+MVVM案例实战(十九)- 自定义字体图标按钮的封装与实现(EF类)

文章目录 1、案例效果1、按钮分类2、E类按钮功能实现与封装1.文件创建与代码实现2、样式引用与封装 3、F类按钮功能实现与封装1、文件创建与代码实现2、样式引用与封装 3、按钮案例演示1、页面实现与文件创建2、运行效果如下 4、源代码获取 1、案例效果 1、按钮分类 在WPF开发…