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

目录

客户端

步骤

ui界面配置​编辑

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

添加模块

构造函数

连接按钮

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

发送按钮

断开按钮

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

服务端

步骤

ui界面配置 

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

添加模块

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

构造函数

新的TCP连接请求时触发

新的数据接收时触发

当连接的状态断掉时触发

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

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

监听按钮

发送按钮

停止监听按钮

断开按钮


客户端

步骤

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位编码的QByteArray
            QByteArray 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();
}

  • 12
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码农小白

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值