qt学习:网络调试助手客户端+服务端

客户端

步骤

ui界面配置

添加头函数,类成员数据,类成员函数

#include <QTcpSocket>
#include <QWidget>private slots://连接按钮void on_btnConnect_clicked();//收到来自服务器的数据触发void mRead_Data_From_Server();//发送按钮void on_btnSend_clicked();//断开按钮void on_btndiscon_clicked();private:QTcpSocket *client;//tcp描述符//向textEditRev文本编辑器中插入指定颜色的文本void mInserTextByColor(Qt::GlobalColor color,QString str);

添加模块

QT       += core gui network

构造函数

    //断开按钮和发送按钮关闭ui->btndiscon->setEnabled(false);ui->btnSend->setEnabled(false);//创建新的QTcpSocket对象client = new QTcpSocket(this);//当client对象的数据可读(收到来自服务器的数据)时,readyRead()信号会被发出,//然后mRead_Data_From_Server()槽函数会被调用以处理接收到的数据connect(client,SIGNAL(readyRead()),this,SLOT(mRead_Data_From_Server()));

连接按钮

//连接按钮
void Widget::on_btnConnect_clicked()
{// 尝试连接到指定的IP地址和端口client->connectToHost(ui->lineEditIPAddr->text(),ui->lineEditPort->text().toInt());// 检查连接状态if(client->state() == QAbstractSocket::ConnectedState ||client->state()==QAbstractSocket::ConnectingState){// 如果连接成功或正在连接中,执行以下操作ui->textEditRev->append("连接成功!"); // 在文本编辑器中添加“连接成功!”的消息  ui->btnConnect->setEnabled(false); // 禁用“连接”按钮,因为它已经完成了连接操作  ui->lineEditPort->setEnabled(false); // 禁用端口输入框,因为连接已经建立  ui->lineEditIPAddr->setEnabled(false); // 禁用IP地址输入框,因为连接已经建立  ui->btndiscon->setEnabled(true); // 启用“断开”按钮,因为现在可以断开连接了  ui->btnSend->setEnabled(true); // 启用“发送”按钮,因为现在可以发送数据了  }
}

收到来自服务器的数据触发

//收到来自服务器的数据触发
void Widget::mRead_Data_From_Server()
{// 将文本编辑器的光标移动到末尾ui->textEditRev->moveCursor(QTextCursor::End);// 确保光标是可见的ui->textEditRev->ensureCursorVisible();// 调用mInserTextByColor函数,将接收到的数据以黑色插入到文本编辑器中 mInserTextByColor(Qt::black,client->readAll());
}

发送按钮

//发送按钮
void Widget::on_btnSend_clicked()
{// 获取文本编辑器textEditSend中的纯文本内容,并将其转换为UTF-8编码的字节数组QByteArray sendData = ui->textEditSend->toPlainText().toUtf8();// 将sendData写入到client对象中,用于发送数据到服务器client->write(sendData);// 调用mInserTextByColor函数,将刚刚发送的数据以红色插入到textEditRev文本编辑器中mInserTextByColor(Qt::red,sendData);
}

断开按钮

//断开按钮
void Widget::on_btndiscon_clicked()
{// 断开与服务器的连接client->disconnectFromHost();// 关闭与服务器的连接client->close();// 在文本编辑器textEditRev中追加文本“断开连接!ui->textEditRev->append("断开连接!");// 启用连接按钮,允许用户重新建立连接  ui->btnConnect->setEnabled(true);// 启用端口输入框,允许用户输入端口号  ui->lineEditPort->setEnabled(true);// 启用IP地址输入框,允许用户输入IP地址  ui->lineEditIPAddr->setEnabled(true);// 禁用断开连接按钮,因为它已经处于断开状态  ui->btndiscon->setEnabled(false);// 禁用发送按钮,因为当前没有与服务器的连接  ui->btnSend->setEnabled(false);
}

向textEditRev文本编辑器中插入指定颜色的文本

//向textEditRev文本编辑器中插入指定颜色的文本
void Widget::mInserTextByColor(Qt::GlobalColor color,QString str)
{// 获取文本编辑器的当前文本光标QTextCursor cursor =  ui->textEditRev->textCursor();// 创建一个文本字符格式对象QTextCharFormat format;// 设置字符格式的前景色为指定的颜色format.setForeground(QBrush(QColor(color)));// 应用字符格式到文本光标cursor.setCharFormat(format);// 在光标位置插入指定的字符串  cursor.insertText(str);
}

服务端

步骤

ui界面配置 

添加头函数,类成员数据,类成员函数

#include <QMessageBox>
#include <QNetworkInterface>
#include <QTcpSocket>
#include <QTextCodec>
#include <QWidget>
#include <QTcpServer>
#include "mycombobox.h"public:QTcpServer* server;//tcp描述符public slots:void on_newClient_connect();//新的TCP连接请求时触发void on_readyRead_handler();//新的数据接收时触发void mdisconnected();//当连接的状态断掉时触发//当 QTcpSocket 的连接状态发生变化时,stateChanged信号会被发出 参数 socketState当前的套接字状态void mstateChanged(QAbstractSocket::SocketState socketState);//当点击通信协议和服务器ip地址的复选框值会发送信号触发mComboBox_refresh函数void mComboBox_refresh();

添加模块

QT       += core gui network

自定义一个继承与复选框类的类,重写鼠标点击事件,定义自定义信号

#ifndef MYCOMBOBOX_H
#define MYCOMBOBOX_H
#include <QComboBox>
#include <QWidget>class MyComboBox : public QComboBox
{Q_OBJECT
public:MyComboBox(QWidget *parent);
protected:void mousePressEvent(QMouseEvent *e) override;
signals:void on_ComboBox_clicked();
};#endif // MYCOMBOBOX_H
#include "mycombobox.h"
#include <QMouseEvent>
MyComboBox::MyComboBox(QWidget *parent) : QComboBox(parent)
{}
void MyComboBox::mousePressEvent(QMouseEvent *e)
{if(e->button() == Qt::LeftButton){emit on_ComboBox_clicked();}QComboBox::mousePressEvent(e);
}

构造函数

    //创建了一个新的QTcpServer对象server = new QTcpServer(this);//当点击通信协议和服务器ip地址的复选框值会发送信号触发mComboBox_refresh函数connect(ui->comboBoxChildren,&MyComboBox::on_ComboBox_clicked,this,&Widget::mComboBox_refresh);//当server对象的newConnection信号被触发时(新的TCP连接请求)on_newClient_connect槽函数会被调用connect(server,SIGNAL(newConnection()),this,SLOT(on_newClient_connect()));//禁用了三个按钮ui->btnLineout->setEnabled(false);ui->btnStopListen->setEnabled(false);ui->btnSend->setEnabled(false);//获取了所有网络接口的地址,并将它们存储在一个QList<QHostAddress>类型的变量addresss中QList<QHostAddress> addresss = QNetworkInterface::allAddresses();//遍历了addresss中的所有地址for(QHostAddress tmp : addresss){//检查该地址是否是一个IPv4地址if(tmp.protocol() == QAbstractSocket::IPv4Protocol){//将该地址的字符串表示添加到comboBoxAddr组合框中ui->comboBoxAddr->addItem(tmp.toString());}}

新的TCP连接请求时触发

//新的TCP连接请求时触发
void Widget::on_newClient_connect()
{// 检查是否有待处理的连接if(server->hasPendingConnections()){// 获取下一个待处理的连接QTcpSocket *connction = server->nextPendingConnection();// 输出客户端的地址和端口到调试信息qDebug() << "client Addr: " << connction->peerAddress().toString() << "port:" << connction->peerPort();// 在文本编辑器中插入客户端的地址和端口信息ui->textEditRev->insertPlainText("客户端地址:"+connction->peerAddress().toString()+"客户端端口号:"+QString::number(connction->peerPort()) +"\n");//::xxx:192.168.1.9// 当连接准备好读取数据时,调用on_readyRead_handler槽函数connect(connction,SIGNAL(readyRead()),this,SLOT(on_readyRead_handler()));// 当连接的状态改变时,调用mstateChanged槽函数并传递新的状态connect(connction,SIGNAL(stateChanged(QAbstractSocket::SocketState)),this,SLOT(mstateChanged(QAbstractSocket::SocketState)));// 将客户端的端口号添加到组合框中,并设置为当前选中的文本ui->comboBoxChildren->addItem(QString::number(connction->peerPort()));ui->comboBoxChildren->setCurrentText(QString::number(connction->peerPort()));// 如果发送按钮当前是禁用的,则启用它if(!ui->btnSend->isEnabled()){ui->btnSend->setEnabled(true);}}
}

新的数据接收时触发

//新的数据接收时触发
void Widget::on_readyRead_handler()
{// sender() 函数返回发出当前信号的对象的指针// 使用 qobject_cast 将发送者转换为 QTcpSocket 指针QTcpSocket *tmpSock = qobject_cast<QTcpSocket *>(sender());// 读取所有可用的数据QByteArray revData = tmpSock->readAll();// 将文本编辑器的光标移动到末尾ui->textEditRev->moveCursor(QTextCursor::End);// 确保光标是可见的ui->textEditRev->ensureCursorVisible();// 在文本编辑器中插入新接收到的数据,前面带有 "客户端: " 的标签ui->textEditRev->insertPlainText("客户端: " + revData);
}

当连接的状态断掉时触发

//当连接的状态断掉时触发
void Widget::mdisconnected()
{// 使用 qobject_cast 将发送者转换为 QTcpSocket 指针QTcpSocket *tmpSock = qobject_cast<QTcpSocket *>(sender());// 在调试输出中打印 "client out!"qDebug() << "client out!";// 在文本编辑器中插入文本,表明客户端已断开连接ui->textEditRev->insertPlainText("客户端断开!");// 计划在事件循环的末尾删除这个 QTcpSocket 对象tmpSock->deleteLater();
}

当 QTcpSocket 的连接状态发生变化时,stateChanged信号会被发出 参数 socketState当前的套接字状态

//当 QTcpSocket 的连接状态发生变化时,stateChanged信号会被发出 参数 socketState当前的套接字状态
void Widget::mstateChanged(QAbstractSocket::SocketState socketState)
{//用于存储组合框中对应端口号的索引int tmpIndex;//将发出信号的对象转换为 QTcpSocket 指针QTcpSocket *tmpSock = qobject_cast<QTcpSocket *>(sender());//使用 qDebug() 打印当前套接字的状态qDebug() << "client out In state:" << socketState;//根据传入的套接字状态 socketState 进行条件判断switch(socketState){//当套接字处于未连接状态时  表示客户端已断开连接case QAbstractSocket::UnconnectedState:ui->textEditRev->insertPlainText("客户端断开!");// 从组合框中移除对应的端口号项tmpIndex = ui->comboBoxChildren->findText(QString::number(tmpSock->peerPort()));ui->comboBoxChildren->removeItem(tmpIndex);// 删除 QTcpSocket 对象tmpSock->deleteLater();// 检查组合框中是否还有该项if(ui->comboBoxChildren->count() == 0)// 禁用发送按钮ui->btnSend->setEnabled(false);break;//当套接字处于已连接  表示有新的客户端接入case QAbstractSocket::ConnectedState://当套接字处于正在连接状态时   表示有新的客户端接入case QAbstractSocket::ConnectingState:ui->textEditRev->insertPlainText("客户端接入!");break;}
}

当点击通信协议和服务器ip地址的复选框值会发送信号触发mComboBox_refresh函数

//当点击通信协议和服务器ip地址的复选框值会发送信号触发mComboBox_refresh函数
void Widget::mComboBox_refresh()
{// 清除组合框中的所有项 ui->comboBoxChildren->clear();// 使用 findChildren 方法获取服务器对象中所有的 QTcpSocket 子对象 QList<QTcpSocket*> tcpSocketClients =  server->findChildren<QTcpSocket*>();// 遍历所有找到的 QTcpSocket 对象for(QTcpSocket* tmp:tcpSocketClients){// 检查对象是否为空if(tmp!=nullptr)// 如果对象不为空,将其对应的端口号添加到组合框中ui->comboBoxChildren->addItem(QString::number(tmp->peerPort()));}// 在组合框中添加 "all" 项ui->comboBoxChildren->addItem("all");
}

监听按钮

//监听按钮
void Widget::on_btnListen_clicked()
{// 从界面上的lineEditPort控件获取用户输入的端口号,并将其转换为整数int port = ui->lineEditPort->text().toInt();// 尝试在指定的地址和端口上启动服务器监听if(!server->listen(QHostAddress(ui->comboBoxAddr->currentText()),port)){qDebug() << "listenError";QMessageBox msgBox;// 创建一个消息框对象msgBox.setWindowTitle("监听失败"); // 设置消息框的标题  msgBox.setText("端口号被占用"); // 设置消息框的文本内容  msgBox.exec(); // 显示消息框  return;}// 如果监听成功,则禁用“开始监听”按钮,启用“停止监听”和“断开”按钮 ui->btnListen->setEnabled(false);ui->btnLineout->setEnabled(true);ui->btnStopListen->setEnabled(true);
}

发送按钮

//发送按钮
void Widget::on_btnSend_clicked()
{// 获取所有已连接的QTcpSocket对象QList<QTcpSocket*> tcpSocketClients =  server->findChildren<QTcpSocket*>();// 如果没有已连接的客户端if(tcpSocketClients.isEmpty()){// 显示一个错误消息框,告知用户当前没有连接 QMessageBox msgBox;msgBox.setWindowTitle("发送错误!");msgBox.setText("当前无连接!");msgBox.exec();// 禁用发送按钮,避免用户重复点击ui->btnSend->setEnabled(false);return;}//当用户不选择向all,所有客户端进行发送的时候if(ui->comboBoxChildren->currentText() != "all"){// 如果用户没有选择"all",则获取当前选中的客户端名称QString currentName = ui->comboBoxChildren->currentText();// 遍历所有已连接的客户端for(QTcpSocket* tmp : tcpSocketClients){// 检查当前客户端的端口号是否与选中的名称匹配if(QString::number(tmp->peerPort()) == currentName){// 如果匹配,则向该客户端发送数据tmp->write(ui->textEditSend->toPlainText().toStdString().c_str());}}}else{//遍历所有子客户端,并一一调用write函数,向所有客户端发送//遍历所有已连接的客户端for(QTcpSocket* tmp:tcpSocketClients){// 将要发送的文本转换为本地8位编码的QByteArrayQByteArray sendData = ui->textEditSend->toPlainText().toLocal8Bit();// 向每个客户端发送数据  tmp->write(sendData);}}
}

停止监听按钮

//停止监听按钮
void Widget::on_btnStopListen_clicked()
{// 获取所有与server关联的QTcpSocket对象QList<QTcpSocket*> tcpSocketClients =  server->findChildren<QTcpSocket*>();// 遍历所有客户端套接字,并关闭它们for(QTcpSocket* tmp:tcpSocketClients){tmp->close();}// 关闭服务器server->close();// 启用“监听”按钮,使其可以再次被点击ui->btnListen->setEnabled(true);ui->btnLineout->setEnabled(false);ui->btnStopListen->setEnabled(false);}

断开按钮

//断开按钮
void Widget::on_btnLineout_clicked()
{// 停止监听按钮on_btnStopListen_clicked();// 释放服务器内存delete server;// 关闭当前窗口this->close();
}

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

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

相关文章

Synchronized方法锁、对象锁、类锁区别

synchronized&#xff0c;这个东西我们一般称之为”同步锁“&#xff0c;他在修饰代码块的时候需要传入一个引用对象作为“锁”的对象。 在修饰方法的时候&#xff0c;默认是当前对象作为锁的对象在修饰类时&#xff0c;默认是当前类的Class对象作为所的对象 故存在着方法锁、…

express+mysql+vue,从零搭建一个商城管理系统10--添加商品

提示&#xff1a;学习express&#xff0c;搭建管理系统 文章目录 前言一、新建models/goods.js二、新建routes/goods.js三、添加goods表四、添加商品总结 前言 需求&#xff1a;主要学习express&#xff0c;所以先写service部分 一、新建models/goods.js models/goods.js con…

跨境电商独立站|代购+集运,这是什么东西?

代购集运&#xff0c;这是什么东西&#xff1f; 跨境集运搭建跨境电商独立站 代购&#xff0c;释义为代理购买。通俗意思就是找人帮忙购买你需要的商品&#xff0c;原因可以是你在当地买不到这件商品&#xff0c;可以是当地这件商品的价格比其他地区的贵&#xff0c;也可以是为…

模拟算法题练习(一)(扫雷,灌溉,回文日期)

目录 模拟算法介绍&#xff1a; &#xff08;一、扫雷&#xff09; &#xff08;二、灌溉&#xff09; &#xff08;三、回文日期&#xff09; 有一说一这题大佬的题解是真的强 模拟算法介绍&#xff1a; 模拟算法通过模拟实际情况来解决问题&#xff0c;一般容易理解但是实…

Windows上构建一个和Linux类似的Terminal

感谢大佬批评指正&#xff0c;现已更新 preview Target&#xff1a;致力打造最赏心悦目Window下的终端&#xff0c;同时能够很接近Linux的使用习惯 key word&#xff1a;windows终端美化 windows terminal windows powershell 类似Linux下的Window终端 Window也能用ll windows…

Linux编程3.1 进程-进程的概念

前情提及&#xff1a; 程序和进程内核中的进程结构C程序启动过程进程终止方式非局部跳转进程资源限制进程创建、执行和终止进程类型进程状态进程组 进程的概念 进程&#xff1a;程序运行&#xff0c;由操作系统内核对该程序进行资源的分配 &#xff0c; 进程中&#xff0c;再…

牛客练习赛122

D:圆 正着求删除的最小代价不好做&#xff0c;采用逆向思维&#xff0c;求选择一些不相交的线段使得构成一个圆的代价尽量大&#xff0c;最后答案就是所有线段权值之和减去最大代价。 那么如何求这个最大代价呢&#xff1f;显然区间DP 老套路&#xff1a;破环成链&#xff0…

【学习心得】网站运行时间轴(爬虫逆向)

一、网站运行时间轴 掌握网站运行时间轴&#xff0c;有助于我们对“请求参数加密”和“响应数据加密”这两种反爬手段的深入理解。 二、从网站运行的时间轴角度来理解两种反爬手段 1、加载HTML&#xff1a; 这是浏览器访问网站时的第一步&#xff0c;服务器会返回基础…

2024|CISP认证详细报考流程和条件

证书介绍 CISP&#xff08;Certified Information Security Professional&#xff0c;注册信息安全专业人员&#xff09;证书是由中国信息安全测评中心&#xff08;CNITSEC&#xff09;颁发的专业资质证书&#xff0c;旨在为信息安全领域培养和认证具备一定专业水平的安全人才…

5.测试教程 - 进阶篇

文章目录 1.按测试对像划分1.1**界面测试**1.2**可靠性测试**1.3**容错性测试**1.4**文档测试**1.5**兼容性测试**1.6**易用性测试**1.7**安装卸载测试**1.8**安全测试**1.9**性能测试**1.10**内存泄漏测试** 2.按是否查看代码划分2.1黑盒测试(Black-box Testing)2.2白盒测试(W…

框架漏洞-->Struts2 Docker_Vulnhub搭建

来浅浅的讲一下Struts2漏洞 目录 1.Docker_Vulnhub搭建 2.Struts2 3.Struts2的框架特征 4.S2-029-->Remote Code Execution 5.漏洞复现 1.RCE 2.Getshell 1.Docker_Vulnhub搭建 因为我用的是Linux&#xff0c;所以我选择直接搭个docker&#xff0c;这里我建议先换个…

绝对定位的一些特性;CSS绝对定位absolute

想要实现如下效果&#xff1a; yellow区域是宽度是100%&#xff1b;想要一个按钮在右侧&#xff0c;且和蓝色区域右侧对齐 思考 毋庸置疑&#xff0c;按钮肯定得使用绝对定位&#xff0c;但是绝对定位的定位位置肯定不能写死&#xff0c;因为这个是个公共组件&#xff0c;黄色…