最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Qt簡單編程實現(xiàn)UDP通訊

 更新時間:2024年04月19日 08:36:22   作者:三號原子  
UDP數(shù)據(jù)報協(xié)議是一個面向無連接的傳輸層報文協(xié)議,它簡單易用,不存在?TCP協(xié)議“粘包”的問題,下面我們就來看看如何使用qt簡單實現(xiàn)UDP通訊吧

UDP通訊

UDP數(shù)據(jù)報協(xié)議是一個面向無連接的傳輸層報文協(xié)議,它簡單易用,不存在 TCP協(xié)議“粘包”的問題,在強調(diào)實時、主動推送的系統(tǒng)中,常常用 UDP協(xié)議來實現(xiàn)網(wǎng)絡雙方的通信。在 Qt 中,QUdpSocket 類提供了 UDP 數(shù)據(jù)報的通信支持,下面通過兩個簡單的例子介紹Qt下 UDP 協(xié)議的實現(xiàn)。

模擬網(wǎng)絡上經(jīng)常定義的數(shù)據(jù)報文結構:

字節(jié)1~45~89~1213~1617~20
定義序號小時分鐘毫秒
#pragma pack(push) //保存對齊狀態(tài)
#pragma pack(4) //設定為4字節(jié)對齊
struct DataStruct{
    unsigned int index;//序號
    int hour;//小時
    int minute;//分鐘
    int second;//秒
    int msec;//毫秒
};
union NetBuffer{
    DataStruct data;
    char dataBuffer[20];
};
#pragma pack(pop) //恢復對齊狀態(tài)

這里用了一個聯(lián)合定義的數(shù)據(jù)緩沖區(qū),便于進行數(shù)據(jù)報文的設置和解析。

需要在 *.pro 工程文件中添加 network 選項 :

QT +=core gui network

基于主窗口的實現(xiàn)

UDP報文的發(fā)送比較隨意,可以在程序的任何需要的時候和位置發(fā)送 UDP報文,為了演示的簡單,本例子中設置了主窗口的定時器,每秒鐘發(fā)送一次報文。在接收的時候,響應接收端口 readyRead()信號,及時讀取網(wǎng)絡協(xié)議緩沖區(qū)的數(shù)值。

1.新建一個工程,在界面中添加兩個列表部件,用于顯示發(fā)送和接收的數(shù)據(jù):

2. 在頭文件中,添加包含 QNetworkInterface、QHostAddress 和 QudpSocket 模塊,添加網(wǎng)絡數(shù)據(jù)報文的結構定義。在 MainWindow 類定義中,添加需要重載的 timerEvent 定義,添加讀取數(shù)據(jù)報文操作 readPendingDatagrams 定義,以及主機地址、發(fā)送和接收 socket和緩沖區(qū)定義。

#ifndef MAINWINDOW_H
#define MAINWINDOW_H
 
#include<QMainWindow>
#include<QtNetwork/QNetworkInterface>
#include<QtNetwork/QHostAddress>
#include<QtNetwork/QUdpSocket>
 
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
 
#pragma pack(push) //保存對齊狀態(tài)
#pragma pack(4) //設定為4字節(jié)對齊
struct DataStruct{
    unsigned int index;//序號
    int hour;//小時
    int minute;//分鐘
    int second;//秒
    int msec;//毫秒
};
union NetBuffer{
    DataStruct data;
    char dataBuffer[20];
};
#pragma pack(pop) //恢復對齊狀態(tài)
 
class MainWindow : public QMainWindow
{
    Q_OBJECT
 
public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();
    void timerEvent(QTimerEvent * event);
 
public slots:
    void readPendingDatagrams();
    
private:
    Ui::MainWindow *ui;
    QHostAddress hostAddress;
    QUdpSocket udpSendSocket,udpRecvSocket;
    NetBuffer sendBuffer,recvBuffer;
};
#endif // MAINWINDOW_H

3. 在 MainWindow 的構造函數(shù)中,獲取本機地址,綁定發(fā)送和接收 socket,設置響應接收 socket 接收信號的槽。

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    //通過調(diào)用靜態(tài)方法獲取本機IP地址
    QList<QHostAddress> addressList = QNetworkInterface::allAddresses();
    hostAddress=addressList.at(0);
    //網(wǎng)絡端口綁定
    udpSendSocket.bind(hostAddress,7000);
    udpRecvSocket.bind(hostAddress,7001);
    //設置定時器
    this->startTimer(1000);
    //初始化發(fā)送計數(shù)器
    sendBuffer.data.index=0;
    //建立接收 socket 的連接
    QObject::connect(&udpRecvSocket,SIGNAL(readyRead()),this,SLOT(readPendingDatagrams()));
}

4.實現(xiàn)發(fā)送和接收操作,并在列表中顯示。發(fā)送操作是在定時器事件響應函數(shù)中實現(xiàn)的,上面已經(jīng)設置了每秒發(fā)送一次。數(shù)據(jù)接收是在 readPendingDatagrams()函數(shù)中實現(xiàn)的,當接收 socket 一有數(shù)據(jù)報文包,readPendingDatagrams()就被調(diào)用,讀取網(wǎng)絡接收到的數(shù)據(jù),并解析顯示。在這里我們用了聯(lián)合的方法來解析網(wǎng)絡數(shù)據(jù)結構,方便易用。

//在 timeEvent 中設置發(fā)送數(shù)據(jù),并在列表中顯示
void MainWindow::timerEvent(QTimerEvent * event){
    QTime tm = QTime::currentTime();//獲取當前時間
    sendBuffer.data.hour=tm.hour();
    sendBuffer.data.minute=tm.minute();
    sendBuffer.data.second=tm.second();
    sendBuffer.data.msec=tm.msec();
    //調(diào)用發(fā)送數(shù)據(jù)包函數(shù),發(fā)送數(shù)據(jù)
    udpSendSocket.writeDatagram (sendBuffer.dataBuffer,sizeof(sendBuffer),hostAddress,7001);
    QString displaystring;
    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'));
    ui->listWidget->insertItem(0,displaystring);
    sendBuffer.data.index++;
}
 
//在 readPendingDatagrams 槽中,接收數(shù)據(jù)并顯示
void MainWindow::readPendingDatagrams (){
    QHostAddress sender;
    quint16 senderPort;
    //調(diào)用數(shù)據(jù)接接收函數(shù),接收數(shù)據(jù)
    udpRecvSocket.readDatagram(recvBuffer.dataBuffer,sizeof (recvBuffer),&sender,&senderPort);
    QString displaystring;
    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'));
    ui->listWidget_2->insertItem(0,displaystring);
}

基于線程的實現(xiàn)

基于窗口部件的 UDP通信實現(xiàn),雖然簡單易用,但是窗口部件主要的工作是負責處理大量的用戶界面信息,當有耗時的處理過程時,會影響數(shù)據(jù)的接收,造成丟幀。通常的做法是用獨立的線程負責網(wǎng)絡數(shù)據(jù)的發(fā)送和接收,再通過窗口部件顯示輸出,在實時系統(tǒng)中這種應用特別廣泛。下面的例子顯示的效果和前面一致,但實現(xiàn)的機理是完全不同的。

1.新建工程,在工程中依次新建發(fā)送和接收線程的C++文件 sendthread. h,sendthread. epp 和 reevthread. h,recvthread. cpp:

其中sendthread.h定義:

#include <QWidget>
#include<QThread>
#include<QtNetwork/QNetworkInterface>
#include<QtNetwork/QHostAddress>
#include<QtNetwork/QUdpSocket>
#include "NetBuffer.h" //就是上文定義的數(shù)據(jù)緩沖
class sendthread :public QThread
{
    Q_OBJECT
public:
    explicit sendthread(QWidget *parent=0);
protected:
    void run();
private:
    QHostAddress hostAddress;
    QUdpSocket udpsendsocket;
    NetBuffer sendBuffer;
};
#endif // SENDTHREAD_H

在 sendthread.h中定義了線程需要用到的主機地址 hostAddress、UDPsocket 端口和發(fā)送緩沖區(qū),定義了線程需要重載的 run()操作。在 sendthread.cpp 的構造函數(shù)中,初始化參數(shù),獲取本機地址,綁定 socket 端口:

#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;
}

然后重載實現(xiàn) run()操作。這里要注意的是,由于主窗口的 ui變量是 protected 類型線程不能直接使用,需要線程通過主窗口的 displaySendData方法,將顯示信息輸出到界面中。

#include<QTime>
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;
    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(1);
    }
}

其中 recvthread.h 的定義:

#include <QWidget>
#include<QThread>
#include<QtNetwork/QNetworkInterface>
#include<QtNetwork/QHostAddress>
#include<QtNetwork/QUdpSocket>
#include "NetBuffer.h"
class recvthread: public QThread
{
    Q_OBJECT
public:
    explicit recvthread(QWidget *parent=0);
protected:
    void run();
private:
    QHostAddress hostAddress;
    QUdpSocket udpRecvSocket;
    NetBuffer recvBuffer;
};

和發(fā)送線程類似,定義了主機地址 hostAddress、UDPsocket 端口和發(fā)送緩沖區(qū),定義了需要重載的 run()操作。在構造函數(shù)中,初始化接收 socket。

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

在 run()中讀取網(wǎng)絡數(shù)據(jù),并通過主窗口的 DisplayRecvData方法顯示。注意這里使用了 waitForReadyRead方法以同步方式讀取數(shù)據(jù),而不是使用信號和槽的異步方法。當沒有新數(shù)據(jù)到來時,線程處于掛起等待狀態(tài),當有數(shù)據(jù)到達時,立刻進入下一步處理,這種方法響應得更及時快速。

#include"mainwindow.h"
void recvthread::run(){
    while (true){
    if(udpRecvSocket.waitForReadyRead()){
        QHostAddress sender;
        quint16 senderPort;
        udpRecvSocket.readDatagram(recvBuffer.dataBuffer,sizeof(recvBuffer),&sender,&senderPort);
        QString displaystring;
        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);
    }
}

2.在主窗口中,初始化發(fā)送和接收 socket 線程,定義 DisplaySendData 和 DisplayRecvData操作顯示收發(fā)數(shù)據(jù)。

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    sendthread *sendThread=new sendthread(this);
    recvthread *recvTrhead=new recvthread(this);
    recvTrhead->start();
    sendThread->start();
}
 
void MainWindow::DisplaySendData(QString displaystring){
    ui->listWidget->insertItem(0,displaystring);
}
 
void MainWindow::DisplayRecvData(QString displaystring){
    ui->listWidget_2->insertItem(0,displaystring);
}

到此這篇關于Qt簡單編程實現(xiàn)UDP通訊的文章就介紹到這了,更多相關Qt UDP通訊內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • c++ 對數(shù)器實現(xiàn)示例

    c++ 對數(shù)器實現(xiàn)示例

    對數(shù)器用于在自己的本地平臺驗證算法正確性,本文詳細的介紹了c++ 對數(shù)器實現(xiàn),文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-08-08
  • 數(shù)組循環(huán)移位操作實例

    數(shù)組循環(huán)移位操作實例

    這篇文章介紹了數(shù)組循環(huán)移位操作實例,有需要的朋友可以參考一下
    2013-09-09
  • 用C語言實現(xiàn)從文本文件中讀取數(shù)據(jù)后進行排序的功能

    用C語言實現(xiàn)從文本文件中讀取數(shù)據(jù)后進行排序的功能

    這是一個十分可靠的程序,這個程序的查錯能力非常強悍。程序包含了文件操作,歸并排序和字符串輸入等多種技術。對大家學習C語言很有幫助,有需要的一起來看看。
    2016-08-08
  • C語言中一些將字符串轉換為數(shù)字的函數(shù)小結

    C語言中一些將字符串轉換為數(shù)字的函數(shù)小結

    這篇文章主要介紹了C語言中一些將字符串轉換為數(shù)字的函數(shù)小結,分別為atoi()函數(shù)和atol()函數(shù)以及atof()函數(shù),需要的朋友可以參考下
    2015-08-08
  • C語言之格式化屏幕輸出詳解

    C語言之格式化屏幕輸出詳解

    這篇文章主要介紹了C語言之格式化屏幕輸出的相關資料,需要的朋友可以參考下,小編覺得這篇文章寫的還不錯,希望能夠給你帶來幫助
    2021-11-11
  • C++小知識:C/C++中不要按值傳遞數(shù)組

    C++小知識:C/C++中不要按值傳遞數(shù)組

    今天小編就為大家分享一篇關于C++小知識:C/C++中不要按值傳遞數(shù)組,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-01-01
  • C++實現(xiàn)LeetCode(206.倒置鏈表)

    C++實現(xiàn)LeetCode(206.倒置鏈表)

    這篇文章主要介紹了C++實現(xiàn)LeetCode(206.倒置鏈表),本篇文章通過簡要的案例,講解了該項技術的了解與使用,以下就是詳細內(nèi)容,需要的朋友可以參考下
    2021-07-07
  • 嵌入式C語言二級指針在鏈表中的應用

    嵌入式C語言二級指針在鏈表中的應用

    這篇文章主要為大家介紹了嵌入式C語言二級指針在鏈表中的應用,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步早日升職加薪
    2022-04-04
  • C++實現(xiàn)LeetCode(148.鏈表排序)

    C++實現(xiàn)LeetCode(148.鏈表排序)

    這篇文章主要介紹了C++實現(xiàn)LeetCode(148.鏈表排序),本篇文章通過簡要的案例,講解了該項技術的了解與使用,以下就是詳細內(nèi)容,需要的朋友可以參考下
    2021-07-07
  • C++實現(xiàn)將長整型數(shù)轉換為字符串的示例代碼

    C++實現(xiàn)將長整型數(shù)轉換為字符串的示例代碼

    這篇文章主要介紹了C++實現(xiàn)將長整型數(shù)轉換為字符串的示例代碼,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-04-04

最新評論

津市市| 阿勒泰市| 炉霍县| 嘉善县| 闵行区| 东源县| 石家庄市| 中方县| 日照市| 定陶县| 卢湾区| 唐山市| 普兰县| 连城县| 民权县| 东乡族自治县| 上思县| 汽车| 天台县| 大关县| 绥棱县| 铅山县| 永登县| 壶关县| 新安县| 兴仁县| 洪湖市| 玉环县| 奇台县| 新民市| 介休市| 东乌珠穆沁旗| 金昌市| 兖州市| 正定县| 凭祥市| 达孜县| 诏安县| 新沂市| 腾冲县| 北票市|