【QT】手把手制作一个网络调试助手(UDP设计)

TCP和UDP网络通信类的使用

Pornhub

1. 程序框架搭建

接着上一篇文章,这里就开始设计UDP的相关功能函数了,首先将其UDP的相关配置进行隐藏;

【QT】手把手制作一个网络调试助手(UDP设计)

1.1 构造函数讲解

MainWindow::MainWindow(QWidget *parent):QMainWindow(parent),ui(new Ui::MainWindow)

其意义是执行父类QWidget的构造函数,创建一个Ui::MainWindow的类对象ui。这个UI就是Widget的private部分定义的指针变量ui。

构造函数里执行了ui->setupUi(this);相当于执行了Ui::Widget类的setupUi()函数,这个函数可以实现窗口的生成与各种属性的设置、信号与槽的关联。

析构函数则是删除new创建的指针ui。 

1.2 屏蔽UDP组件

我们希望在界面初始状态下UDP的组件不被显示出来。

    ui->txtUdpTxIP->hide();
    ui->spbUdpTxPort->hide();
    ui->cbbTxPort->hide();

1.3 声明UDP对象

在头文件中的private中申明一个UDP类的对象;

QUdpSocket *udp;

再在.cpp中进行申明;

udp = new QUdpSocket(this);

2. UI初始化准备工作

2.1 列出支持的网络通信类型

头文件public:初始化:void listNetworkType(QComboBox *cbbNetworkType);

/**
 * @brief MainWindow::listNetworkType 列出支持的网络通信类型
 * @param cbbNetworkType
 */
void MainWindow::listNetworkType(QComboBox *cbbNetworkType)
{
    QMetaEnum mtaEnum = QMetaEnum::fromType<MainWindow::NetworkType>();
    for (int i = 0; i < mtaEnum.keyCount(); i++) {
        cbbNetworkType->addItem(mtaEnum.key(i), mtaEnum.value(i));
    }
    cbbNetworkType->setCurrentText("UDP"); // 设定默认值
}

2.2 获取主机的IPV4

头文件public:初始化:QStringList getHostAddress();

/**
 * @brief MainWindow::getHostAddress 获取主机的 IPv4
 */
QStringList MainWindow::getHostAddress()
{
    QList<QHostAddress> addrList = QNetworkInterface::allAddresses();
    QStringList tmp;
    foreach (QHostAddress hostAddr, addrList){
        if(hostAddr.protocol() == QAbstractSocket::IPv4Protocol){
            if(hostAddr.toString().contains("127.0.")) continue;
            tmp<<hostAddr.toString();
        }
        else if (hostAddr.isNull())  // 主机地址为空
            continue;
    }
    return tmp;
}

2.3 UDP、TCP模式下界面修改

头文件public:初始化:void initComboBoxUDP();

void MainWindow::initComboBoxUDP()
{
    ui->lblIP->setText("本地IP");
    ui->btnLink->setText("连接");
    ui->cbbTxPort->hide();
    ui->txtUdpTxIP->show();
    ui->spbUdpTxPort->show();
}

TCPServer模式下界面修改 

void initComboBoxServer();

void initComboBoxClient();

/**
 * @brief MainWindow::initComboBoxServer 界面修改 服务器
 */
void MainWindow::initComboBoxServer()
{
    ui->lblIP->setText("本地IP");
    ui->btnLink->setText("监听");
    ui->txtUdpTxIP->hide();
    ui->spbUdpTxPort->hide();
    ui->cbbTxPort->show();
}
/**
 * @brief MainWindow::initComboBoxClient 界面修改 客户端
 */
void MainWindow::initComboBoxClient()
{
    ui->lblIP->setText("远程IP");
    ui->btnLink->setText("连接");
    ui->txtUdpTxIP->hide();
    ui->spbUdpTxPort->hide();
    ui->cbbTxPort->show();
}

2.4 UDP初始化下拉列表

头文件public:初始化:void initComboBox_Config();

/**
 * @brief MainWindow::initComboBox_Config 初始化下拉列表
 *
 */
void MainWindow::initComboBox_Config()
{
    this->listNetworkType( ui->cbbNetType );
    QStringList hostAddrList = getHostAddress();
    if( !hostAddrList.isEmpty() )
        ui->txtIP->setText( hostAddrList.at(0) );
    this->initComboBoxUDP();
}

2.5 下拉列表切换三种通信模式

【QT】手把手制作一个网络调试助手(UDP设计)

/**
 * @brief MainWindow::on_cbbNetType_currentIndexChanged 切换通信模式
 * @param index
 */
void MainWindow::on_cbbNetType_currentIndexChanged(int index)
{
    switch(index){
    case TCPServer:
        this->initComboBoxServer();
        break;
    case TCPClient:
        this->initComboBoxClient();
        break;
    case UDP:
        this->initComboBoxUDP();
        break;
    }
}

2.6 连接按钮事件

获取下拉列表的值:

    enum NetworkType{
        TCPServer  = 0,
        TCPClient  = 1,
        UDP        = 2,
    };
    Q_ENUM(NetworkType)
    NetworkType networkType = (NetworkType)ui->cbbNetType->currentIndex();

列出枚举的类型,根据下拉列表读取当时的值;

然后进行判断,如果已经点击连接按键;判断下拉列表的值,如果是TCPServer则进行监听,如果是TCPClient则进行连接远端的服务器,如果是UDP则绑定端口号;

如果没有点击连接,则断开上述接口;

在头文件声明指针;

   QTcpServer *server;
    QTcpSocket *client;
    QList<QTcpSocket *>clients;
void MainWindow::on_btnLink_clicked(bool checked)
{
    NetworkType networkType = (NetworkType)ui->cbbNetType->currentIndex();

    bool ok = false;
    if(checked){
        switch(networkType){
        case TCPServer:
      //      ok = this->startListen();
            break;
        case TCPClient:
     //       ok = this->connectRemoteServer();
            break;
        case UDP:
     //       ok = this->bindAddrAndPort();
            break;
        }
        ok? ui->cbbNetType->setEnabled(false): ui->cbbNetType->setEnabled(true);
    }else{
        switch(networkType){
        case TCPServer:
      //      this->stopListen();
            break;
        case TCPClient:
     //       this->disconnectRemoteServer();
            break;
        case UDP:
      //      this->unbindAddrAndPort();
            break;
        default:break;
        }
        ui->cbbNetType->setEnabled(true);
    }
}

现在根据上述流程,将相关函数进行完善;

2.7 UDP通信

UDP每次发送数据报都要指定目标地址端口号;

QUdpSocket *udp;在头文件中声明UDP类用于实现UDP通信;

进行UDP数据接收需要使用

QUdpSocket::bid()函数绑定一个端口;用于接收传入数据报,

udp->bind( *ip, port );

获取客户端IP;获取端口号;

监听函数,返回bool值;

2.7.1 添加状态显示StatusBar

【QT】手把手制作一个网络调试助手(UDP设计)

右击,选择添加状态栏;

在提升类的名称中命名为statusBar

【QT】手把手制作一个网络调试助手(UDP设计)

ui->statusBar->showMessage("正在监听");

 2.7.2 定义槽函数

public slots:
    void slots_udpRxCallback();

2.7.3 插入时间戳

/**
 * @brief MainWindow::insertTimeStamp 插入时间戳前缀
 * @param tmp
 */
void MainWindow::insertTimeStamp(QString &tmp)
{
    QTime currentTime = QTime::currentTime();
    tmp.prepend( "[" + currentTime.toString("hh:mm:ss:zzz") + "]");
}

2.7.4 数据记录在RxBrowser中

/**
 * @brief MainWindow::logInRxBrowser 数据记录在RxBrowser中
 * @param ipInfo ip,port
 * @param tmp
 */
void MainWindow::logInRxBrowser(QString ipInfo, QByteArray &tmp)
{
    if(ui->ckbTimeStamp->isChecked())
        this->insertTimeStamp(ipInfo);

    QString msg;
    if( ui->ckbHexRx->isChecked() ){
        msg = tmp.toHex(' ').toUpper();
    }else{
        msg = QString::fromLocal8Bit(tmp);
    }
    ui->txtRxBrowser->append( ipInfo + msg );
}

判断;时间戳添加;

判断;转化为十六进制;

txtRxBrowser文本框输出ip信息和数据信息

2.7.5 发出信息插入服务器信息

/**
 * @brief MainWindow::insertServerInfo 插入服务器信息
 * @param tmp
 */
void MainWindow::insertTxInfo(QString &tmp)
{
    QString ip ;
    QString port;
    NetworkType networkType = (NetworkType)ui->cbbNetType->currentIndex();
    switch(networkType){
  case TCPServer :
        ip       = server->serverAddress().toString();
        port     = QString::number( server->serverPort() );
        break;
    case TCPClient:
        ip       = client->localAddress().toString();
        port     = QString::number( client->localPort() );
        break;
    case UDP:
        ip       = ui->txtIP->text();
        port     = ui->txtPort->text();
        break;
    }
    tmp.prepend( "[" + QString("Tx from %1:%2").arg(ip, port) +"]\n" );
}

2.7.6 接收插入发送端IP和端口号

/**
 * @brief MainWindow::insertRxInfo 插入发送端的IP和端口号
 * @param client
 * @param tmp
 */
void MainWindow::insertRxInfo(QNetworkDatagram *datagram, QString &tmp)
{
    QString ip = datagram->senderAddress().toString();
    QString port = QString::number( datagram->senderPort() );
    tmp.prepend( "[" + QString("Rx from %1:%2").arg(ip, port) +"]\n" );
}

上一篇:Spring笔记Day1


下一篇:jQuery使用详细使用篇day1