版权声明:本文为博主原创文章,未经博主允许不得转载。 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秒发送一次数据
}
}
头文件:
#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);
}
}
}
#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