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.rhkb.cn/news/462888.html

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

相关文章

【CSS3】css开篇基础(5)

1.❤️❤️前言~&#x1f973;&#x1f389;&#x1f389;&#x1f389; Hello, Hello~ 亲爱的朋友们&#x1f44b;&#x1f44b;&#xff0c;这里是E绵绵呀✍️✍️。 如果你喜欢这篇文章&#xff0c;请别吝啬你的点赞❤️❤️和收藏&#x1f4d6;&#x1f4d6;。如果你对我的…

C++学习路线(数据库部分)二

类型 整形类型 整数类型是数据库中最基本的数据类型。标准SQL中支持INTEGER和SMALLINT这两种数据类型。MySQL数据库除了支持这两种类型以外&#xff0c;还扩展支持了TINYINT、MEDIUMINT和BIGINT。下表从不同整数类型的字节数、取值范围等方面进行对比。 类型名称后面的小括号…

IDEA中通义灵码的使用技巧

大家好&#xff0c;我是 V 哥。在日常写代码的过程中&#xff0c;通过 AI 工具辅助开发已是当下程序员惯用的方式&#xff0c;V 哥在使用了众多的 AI 工具后&#xff0c;多数情况下&#xff0c;选择通义灵码来辅助开发&#xff0c;尤其是解释代码和生成单元测试功能甚是好用&am…

Docker篇(实际应用)

目录 一、MySQL 部署 1. 拉取 MySQL 镜像 2. 查看镜像 3. 创建 MySQL 容器 4. 进入 MySQL 容器,登陆 MySQL 5. 远程登陆 MySQL 6. 查看容器 IP 地址 二、tomcat 部署 1. 拉取 tomcat 镜像 2. 创建 tomcat 容器 3. 搭建 Tomcat 服务并部署 web 应用 三、Nginx 部署 …

Darknet 连接教程

本篇文章仅供学习&#xff0c;严禁用于非法用途。 1&#xff0c;前言&#xff1a; 首先明确一点&#xff0c;Darknet真没那么神奇&#xff0c;虽然有些技术文章的确很有水平&#xff0c;对于前端学习&#xff0c;软件开发以及PHP和一些服务器端维护都有许多文章&#xff0c;但…

江协科技STM32学习- P33 实验-软件I2C读写MPU6050

&#x1f680;write in front&#x1f680; &#x1f50e;大家好&#xff0c;我是黄桃罐头&#xff0c;希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流 &#x1f381;欢迎各位→点赞&#x1f44d; 收藏⭐️ 留言&#x1f4dd;​…

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…

立刻解决 gcc: error: unrecognized argument in option ‘-mabi=aapcs-linux’

unrecognized argument in option ‘-mabiaapcs-linux’ Linux 主线支持的硬件较少&#xff0c;一般是第三方开源&#xff08; Linaro/Yocto &#xff09;或者硬件厂商提供定制的嵌入式 Linux 如果确认主线支持自己的硬件&#xff0c;可以从 https://www.kernel.org/ 获取指定…

「Mac畅玩鸿蒙与硬件23」鸿蒙UI组件篇13 - 自定义组件的创建与使用

自定义组件可以帮助开发者实现复用性强、逻辑清晰的界面模块。通过自定义组件,鸿蒙应用能够提高代码的可维护性,并简化复杂布局的构建。本篇将介绍如何创建自定义组件,如何向组件传递数据,以及如何在不同页面间复用这些组件。 关键词 自定义组件复用组件属性传递组件通信组…

Windows版 nginx安装,启动,目录解析,常用命令

Windows版 nginx安装&#xff0c;启动&#xff0c;目录解析&#xff0c;常用命令 一级目录二级目录三级目录 1. 下载2. 启动方式一&#xff1a;方式二&#xff1a; 3. 验证是否启动4. 安装目录解析5. 常用命令 一级目录 二级目录 三级目录 1. 下载 官网下载&#xff1a;ngi…

Oracle视频基础1.3.7练习

1.3.7 看oracle是否启动构造一个pfile:boobooke.ora看spfilewilson内容修改alert log file里拷贝的参数内容&#xff0c;创建一个pfile boobooke.ora用新创建的pfile启动数据库&#xff0c;并创建新的spfile:spfilebbk.ora启动数据库&#xff0c;监听&#xff0c;看新的进程解…

【LeetCode】每日一题 2024_11_2 使两个整数相等的位更改次数(位运算/模拟)

前言 每天和你一起刷 LeetCode 每日一题~ LeetCode 启动&#xff01; 题目&#xff1a;使两个整数相等的位更改次数 代码与解题思路 先读题&#xff1a; 题目要我们把 n 这个数字转换成 k 这个数字&#xff0c;但是只能是二进制位 1 转换成 0 纯模拟的解法&#xff1a; f…

鸿蒙生态下开发挑战-鸿蒙低代码开发工具展望及优势

鸿蒙生态下开发挑战 在鸿蒙生态下开发时&#xff0c;开发者可能会遇到多方面的挑战&#xff0c;这些挑战主要涉及开发工具、技术难度、生态竞争以及市场定位等方面。以下是对这些挑战的详细分析&#xff1a; 一、开发工具不完善 尽管鸿蒙系统的开发工具DevEco Studio在逐步完…

typescript 如何跳过ts类型检查?

文章目录 前言any类型条件判断进行使用断言加注释跳过ts检查 前言 typescript 的使用&#xff0c;虽然让代码更加规范&#xff0c;利于维护&#xff0c;但也给开发带来很多麻烦。为了跳过很多ts的类型检查&#xff0c;大家也是费尽心思&#xff0c;下面就介绍一些常用的方式&a…

(八)JavaWeb后端开发——Tomcat

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

Leetcode - 142双周赛

目录 一&#xff0c;3330. 找到初始输入字符串 I 二&#xff0c;3331. 修改后子树的大小 三&#xff0c;3332. 旅客可以得到的最多点数 四&#xff0c;3333. 找到初始输入字符串 II 一&#xff0c;3330. 找到初始输入字符串 I 本题就是一道找规律的题&#xff0c;拿示例一来…

使用python画一颗圣诞树

具体效果&#xff1a; 完整代码&#xff1a; import random def print_christmas_tree(height): # 打印圣诞树的顶部 for i in range(height): # 打印空格&#xff0c;使树居中 for j in range(height - i - 1): print(" ", end"") # 打印星号&…

camera和lidar外参标定

雷达和相机的外参标定&#xff08;外部参数标定&#xff09;指的是确定两者之间的旋转和平移关系&#xff0c;使得它们的坐标系可以对齐。 文章目录 无目标标定livox_camera_calibdirect_visual_lidar_calibration 有目标标定velo2cam_calibration 无目标标定 livox_camera_ca…

《使用Gin框架构建分布式应用》阅读笔记:p307-p392

《用Gin框架构建分布式应用》学习第16天&#xff0c;p307-p392总结&#xff0c;总86页。 一、技术总结 1.AWS chapter 08讲使用AWS进行部署&#xff0c;可以根据需要选择是否阅读。因为使用到的概率很小&#xff0c;且还要绑卡&#xff0c;本人选择跳过。 2.CI/CD (1)什么…

【初阶数据结构】实现顺序结构二叉树->堆(附源码)

文章目录 须知 &#x1f4ac; 欢迎讨论&#xff1a;如果你在学习过程中有任何问题或想法&#xff0c;欢迎在评论区留言&#xff0c;我们一起交流学习。你的支持是我继续创作的动力&#xff01; &#x1f44d; 点赞、收藏与分享&#xff1a;觉得这篇文章对你有帮助吗&#xff1…