UDP通信之线程实现

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u013776188/article/details/76242227

比较:窗口通信的不足之处:窗口部件主要处理大量的用户界面信息,当有耗时的处理过程时,会影响数据接收,造成丢帧。

   线程通信的好处:通常使用独立的线程负责网络数据的发送和接收,在通过窗口部件进行数据显示,在实时系统同这种应用十分广泛。


基于线程实现UDP数据的收发:

step1:新建窗口程序工程,添加发送数据线程类SendThread和接收数据线程类RecvThread,均继承QThread

step2:单独新建头文件netbuffer.h,在头文件中定义网络数据报文的结构。

#ifndef NETBUFFER_H
#define NETBUFFER_H

namespace NetWork{
    //数据报文结构
    #pragma pack(push)  //保存对齐状态
    #pragma pack(4)     //设定为4字节对齐状态
    struct DataStruct{
        unsigned int index;
        int hour;
        int minute;
        int second;
        int msec;
    };

    //数据缓冲区
    union NetBuffer{
        DataStruct data;
        char dataBuffer[20];
    };
    #pragma pack(pop)   //恢复字节对齐状态
}
#endif // NETBUFFER_H

step3:在发送数据线程类中定义主机地址,发送端socket和发送数据缓冲区,并且重写run方法

头文件:

#ifndef SENDTHREAD_H
#define SENDTHREAD_H
#include <QThread>
#include <QtNetwork/QHostAddress>
#include <QtNetwork/QNetworkInterface>
#include <QtNetwork/QUdpSocket>
#include <QTime>
#include "mainwindow.h"
#include "netbuffer.h"
class SendThread:public QThread
{
    Q_OBJECT
public:
    explicit SendThread(QWidget *parent = 0);

protected:
    void run();
private:
    QHostAddress hostAddress;
    QUdpSocket udpSendSocket;
    NetWork::NetBuffer sendBuffer;

};

#endif // SENDTHREAD_H
实现文件:

#include "sendthread.h"

SendThread::SendThread(QWidget *parent):QThread(parent)
{
    QList<QHostAddress> addressList = QNetworkInterface::allAddresses();
    hostAddress = addressList.at(0);
    udpSendSocket.bind(hostAddress,7000);
    sendBuffer.data.index = 0;
}

void SendThread::run()
{
    while(true){
        QTime tm = QTime::currentTime();
        sendBuffer.data.hour = tm.hour();
        sendBuffer.data.minute = tm.minute();
        sendBuffer.data.second = tm.second();
        sendBuffer.data.msec = tm.msec();
        udpSendSocket.writeDatagram(sendBuffer.dataBuffer,sizeof(sendBuffer),hostAddress,7001);
        QString displayString = QString("Index:%1\nTime:%2:%3:%4.%5\n")
                .arg(sendBuffer.data.index)
                .arg(sendBuffer.data.hour,2,10,QChar('0'))
                .arg(sendBuffer.data.minute,2,10,QChar('0'))
                .arg(sendBuffer.data.second,2,10,QChar('0'))
                .arg(sendBuffer.data.msec,3,10,QChar('0'));
        ((MainWindow*)this->parent())->DisplaySendData(displayString);
        sendBuffer.data.index++;
        this->sleep(5);//设置5秒发送一次数据
    }
}


step4:类似发送端操作,在接收端定义主机地址,接收端socket和接收数据缓冲区并且绑定ip和端口,具体操作如下

头文件:

#ifndef RECVTHREAD_H
#define RECVTHREAD_H
#include <QThread>
#include <QtNetwork/QHostAddress>
#include <QtNetwork/QNetworkInterface>
#include <QtNetwork/QUdpSocket>
#include <QTime>
#include "mainwindow.h"
#include "netbuffer.h"

class RecvThread:public QThread
{
    Q_OBJECT
public:
    explicit RecvThread(QWidget *parent = 0);

private:
    QHostAddress hostAddress;
    QUdpSocket udpRecvSocket;
    NetWork::NetBuffer RecvBuffer;
protected:
    void run();
};

#endif // RECVTHREAD_H


实现文件:

#include "recvthread.h"

RecvThread::RecvThread(QWidget *parent):QThread(parent)
{
    QList<QHostAddress> addressList = QNetworkInterface::allAddresses();
    hostAddress = addressList.at(0);
    udpRecvSocket.bind(hostAddress,7001);
}

void RecvThread::run()
{
    while(true){
        if(udpRecvSocket.waitForReadyRead()){
            QHostAddress senderIP;
            quint16 senderPort;
            udpRecvSocket.readDatagram(RecvBuffer.dataBuffer,sizeof(RecvBuffer),&senderIP,&senderPort);
            QString displayString = QString("Index:%1\nTime:%2:%3:%4.%5\n")
                    .arg(RecvBuffer.data.index)
                    .arg(RecvBuffer.data.hour,2,10,QChar('0'))
                    .arg(RecvBuffer.data.minute,2,10,QChar('0'))
                    .arg(RecvBuffer.data.second,2,10,QChar('0'))
                    .arg(RecvBuffer.data.msec,3,10,QChar('0'));
            ((MainWindow*)this->parent())->DisplayRecvData(displayString);
        }
    }
}


step5:在主窗口构造函数中初始化发送和接收socket线程,并且在主窗口中定义DisplaySendData和DisplayRecvData操作显示收发数据。

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    SendThread *sendThread = new SendThread(this);
    RecvThread *recvThread = new RecvThread(this);
    recvThread->start();
    sendThread->start();
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::DisplaySendData(QString displayString)
{
    ui->listWidget->insertItem(0,displayString);
}

void MainWindow::DisplayRecvData(QString displayString)
{
    ui->listWidget_2->insertItem(0,displayString);
}

step6:最后不能忘记在*.pro文件中添加如下代码,不添加程序会报“无法解析的外部命令”的错误。

QT  += core gui network






猜你喜欢

转载自blog.csdn.net/u013776188/article/details/76242227