国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Qt —UDP通信QUdpSocket 簡介 +案例

這篇具有很好參考價值的文章主要介紹了Qt —UDP通信QUdpSocket 簡介 +案例。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

1. UDP通信概述


? ?UDP是無連接、不可靠、面向數據報(datagram)的協議,可以應用于對可靠性要求不高的場合。與TCP通信不同,UDP通信無需預先建立持久的socket連接,UDP每次發(fā)送數據報都需要指定目標地址和端口。

? ?QUdpSocket以數據報傳輸數據,而不是以連續(xù)的數據流。發(fā)送數據報使用函數??? ? ? ?QUdpSocket::writeDatagram(),數據報的長度一般少于512字節(jié),每個數據報包含發(fā)送者和接收者的IP地址和端口等信息。
? ? ?UDP數據接收,首先要使用QUdpSocket::bind()綁定一個端口,綁定端口后,socket的狀態(tài)會變?yōu)橐呀壎顟B(tài)“BoundState”。

當有數據報傳入時,QudpSocket會自動發(fā)射readyRead()信號,在其槽函數中使用QUdpSocket::readDatagram()進行數據讀取。abort()為解除綁定,解除后socket狀態(tài)變?yōu)槲催B接狀態(tài)“UnconnectedState”。

2. UDP消息傳送的三種模式

單播模式(unicast):一個UDP客戶端發(fā)送數據報到指定地址和端口的另一UDP客戶端,是一對一的數據傳輸。

廣播模式(broadcast):一個UDP客戶端發(fā)出的數據報,在同一網絡范圍內其他所有的UDP客戶端都可以收到。QUdpSocket支持IPv4廣播。需要在數據報中指定接收端地址為QHostAddress::Broadcast,一般的廣播地址是255.255.255.255。

組播模式(multicast):UDP客戶端加入到另一個組播IP地址的多播組,成員向組播地址發(fā)送的數據報,其加入組播的所有成員都可以接收到,類似于QQ群功能。QUdpSocket::joinMulticastGroup()函數實現加入多播組的功能。

QUdpSocket::leaveMulticastGroup()函數實現

在單播、廣播和多播模式下,UDP程序都是對等的,不像TCP通信分為客戶端和服務端。
TCP通信只有單播模式。UDP通信雖然不能保證數據傳輸的準確性,但是具有靈活性,一般的即時通信軟件都是基于UDP通信的。

3. QUdpSocket類的接口函數

bool bind(quint16 port = 0)? 為UDP通信綁定一個端口

qint64 writeDatagram(QByteArray& datagram, QHostAddress& host, quint16 port) 向目標地址和端口的UDP客戶端發(fā)送數據報,返回成功發(fā)送的字節(jié)數,數據報的長度一般不超過512字節(jié)。

bool hasPendingDatagrams()? ? ?當至少有一個數據報需要讀取時,返回true

qint64 pendingDatagramSize()? ? 返回第一個待讀取的數據報的大小

qint64 readDatagram(char* data, qint64 maxSize) 讀取一個數據報,返回成功讀取的字節(jié)數

qint64 readDatagram(char* data, qint64 maxSize, QHostAddress* address, quint16* port) 讀取一個數據報,返回成功讀取的字節(jié)數。發(fā)送方的主機地址和端口存儲在*address和*port中(除非指針為0)

bool joinMulticastGroup(QHostAddress& groupAddress)? ? ? 加入一個多播組

bool leaveMulticastGroup(QHostAddress& groupAddress)? ??離開一個多播組

void abort() 終止當前連接并重置套接字。通常在析構函數中寫入。與disconnectFromHost()不同,該函數立即關閉套接字,丟棄寫入緩沖區(qū)中的任何掛起數據。
原文鏈接:https://blog.csdn.net/WL0616/article/details/129050373

4.UDP對話小案例

實現發(fā)送和接收端互相發(fā)信息,類似QQ? (界面使用UI設計)

4.1.接收端

receiver.h

#ifndef RECESIVER_H
#define RECESIVER_H

#include <QWidget>
#include <QUdpSocket>
QT_BEGIN_NAMESPACE
namespace Ui { class Recesiver; }
QT_END_NAMESPACE

class Recesiver : public QWidget
{
    Q_OBJECT

public:
    Recesiver(QWidget *parent = nullptr);
    ~Recesiver();

private slots:
    void on_pushButton_2_clicked(); //啟動槽函數
    void start();
    void on_pushButton_clicked();

private:
    Ui::Recesiver *ui;
    QUdpSocket *receiver;
};
#endif // RECESIVER_H

receiver.cpp

#include "recesiver.h"
#include "ui_recesiver.h"

Recesiver::Recesiver(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Recesiver)
{
    ui->setupUi(this);
    setWindowTitle(QStringLiteral("接收端"));
    ui->lineEdit->setText("127.0.0.1");
    receiver =new QUdpSocket(this);
}

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

//接收信息
 void Recesiver::start()
 {
    QByteArray datagram;
    datagram.resize(receiver->pendingDatagramSize()); //接收到的數據的長度
    receiver->readDatagram(datagram.data(),datagram.size());
    ui->textEdit->append(QStringLiteral("對方:")+datagram);
 }

//啟動按鈕(發(fā)送端發(fā)送信息給接收端)
void Recesiver::on_pushButton_2_clicked()
{
   receiver->bind(ui->lineEdit_2->text().toInt());//設置端口號將其轉為整型
   connect(receiver,&QUdpSocket::readyRead,this,[&](){start();});
   ui->pushButton_2->setEnabled(false);
   ui->lineEdit_2->setEnabled(false);
}

//發(fā)送按鈕(接收端發(fā)送信息給發(fā)送端)
void Recesiver::on_pushButton_clicked()
{
    QByteArray datagram=ui->textEdit_2->toPlainText().toUtf8();  //在輸入端輸入發(fā)送的內容
    receiver->writeDatagram(datagram.data(),datagram.size(),QHostAddress(ui->lineEdit->text()),ui->lineEdit_3->text().toInt());
    //qint64 writeDatagram(const char *data, qint64 len, const QHostAddress &host, quint16 port);
    //發(fā)送數據,大小,發(fā)送主機的ip,發(fā)送主機的端口號
    ui->textEdit->append(QStringLiteral("本機:")+ui->textEdit_2->toPlainText());//發(fā)送信息的具體內容在發(fā)送端的聊天記錄里能體現
    ui->textEdit_2->clear();
}

4.2發(fā)送端

sender.h

#ifndef SENDER_H
#define SENDER_H
#include <QWidget>
#include <QUdpSocket>
QT_BEGIN_NAMESPACE
namespace Ui { class Sender; }
QT_END_NAMESPACE

class Sender : public QWidget
{
    Q_OBJECT

public:
    Sender(QWidget *parent = nullptr);
    ~Sender();
    void  start2();
private slots:
    void on_pushButton_clicked();

private:
    Ui::Sender *ui;
    QUdpSocket *sender;
};
#endif // SENDER_H

sender.cpp

#include "sender.h"
#include "ui_sender.h"

Sender::Sender(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Sender)
{
    ui->setupUi(this);
    sender=new QUdpSocket(this);
    setWindowTitle(QStringLiteral("發(fā)送端"));

    //sender
    ui->lineEdit_3->setText("888");
    sender->bind(ui->lineEdit_3->text().toInt());//綁定端口號

    connect(sender,&QUdpSocket::readyRead,this,[&](){start2();});
    //start2();
}

void Sender::start2()
{
    QByteArray datagram;
    datagram.resize(sender->pendingDatagramSize()); //接收到的數據的長度
    sender->readDatagram(datagram.data(),datagram.size());
    ui->textEdit->append(QStringLiteral("對方:")+datagram);
}


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


//發(fā)送按鈕 發(fā)送信息給接收端
void Sender::on_pushButton_clicked()
{
   QByteArray datagram=ui->textEdit_2->toPlainText().toUtf8();  //在輸入端輸入發(fā)送的內容
   sender->writeDatagram(datagram.data(),datagram.size(),QHostAddress(ui->lineEdit->text()),ui->lineEdit_2->text().toInt());
   //qint64 writeDatagram(const char *data, qint64 len, const QHostAddress &host, quint16 port);
   //發(fā)送數據,大小,發(fā)送主機的ip,發(fā)送主機的端口號
   ui->textEdit->append(QStringLiteral("本機:")+ui->textEdit_2->toPlainText());//發(fā)送信息的具體內容在發(fā)送端的聊天記錄里能體現
   ui->textEdit_2->clear();

}

結果:

(ps:對話有點搞笑,哈哈哈)

Qt —UDP通信QUdpSocket 簡介 +案例,qt,udp,開發(fā)語言

5.4. UDP單播和廣播代碼示例

4.1 測試說明

? 本實例實現UDP通信的單播和廣播。兩個實例可以運行在同一臺計算機上,也可以運行在不同的計算機上。
這里的兩個實例是運行在同一臺計算機上,需要注意,在同一臺計算機上運行時,兩個實例需要綁定不同的端口。例如實例A綁定端口1600,實例B綁定端口3200,實例A向實例B發(fā)送數據報時,需要指定實例B的端口,這樣實例B才能收到數據。
如果兩個實例在不同的計算機上運行,則端口可以一樣,因為IP地址不同了,不會導致綁定時發(fā)生沖突。一般的UDP通信程序都是在不同的計算機上運行的,約定一個固定的端口作為通信端口。

4.2主要程序

用UI設計器件和代碼化UI分別設計

ui設計器設計:

.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QLabel>
#include <QAbstractSocket>
#include <QUdpSocket>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();
    void   handleEvents();                                                 // 信號與槽處理

private:
    Ui::MainWindow *ui;

    QUdpSocket *udpScoket;
    QLabel *labstateScoket;   //Scoket狀態(tài)欄標簽
    QString  getLocalIp();  //獲取本機的IP地址
private slots:

    void slotActBindPort();   //綁定端口
    void slotActUnbindPort(); //解除端口
    void slotActClearText();  //清空文本框
    void slotActQuit();       //退出

    void slotSocketReadyRead();  //讀取socket傳入的數據
    void slotSocketStateChanged(QAbstractSocket::SocketState socketState);

    void on_pushButton_clicked(); //發(fā)送信息
    void on_pushButton_2_clicked(); //廣播信息
};
#endif // MAINWINDOW_H

.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QTextEdit>
#include <QMessageBox>
#include <QHostInfo>

#include <QAction>
#include <QPushButton>
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    QString localIP = getLocalIp(); //獲取本機的IP地址
    this->setWindowTitle(this->windowTitle() + "---IP:" + localIP);

    ui->comboBox->addItem(localIP); //在目標地址中添加IP
    udpScoket = new QUdpSocket(this);

    //狀態(tài)欄
    labstateScoket = new QLabel(QStringLiteral("socket狀態(tài):"), this);
    labstateScoket->setMinimumWidth(150);
    ui->statusBar->addWidget(labstateScoket);
    handleEvents();

    ui->spinBox->setMinimum(1);     //設置綁定端口的最大最小值和當前的端口值
    ui->spinBox->setMaximum(65535);
    ui->spinBox->setValue(1600);

    ui->spinBox_2->setMinimum(1);   //設置目標端口的最大最小值和當前的端口值
    ui->spinBox_2->setMaximum(65535);
    ui->spinBox_2->setValue(3200);

}

MainWindow::~MainWindow()
{
    udpScoket->abort();
    delete udpScoket;
    udpScoket = nullptr;
    delete ui;
}


// 信號與槽處理
void MainWindow::handleEvents()
{

    connect(ui->action, &QAction::triggered, this, &MainWindow::slotActBindPort );
    connect(ui->action_2, &QAction::triggered, this, &MainWindow::slotActUnbindPort);
    connect(ui->action_3, &QAction::triggered, this, &MainWindow::slotActClearText);
    connect(ui->action_4, &QAction::triggered, this, &MainWindow::slotActQuit);

    connect(ui->pushButton, &QPushButton::clicked, this, &MainWindow::on_pushButton_clicked);
    connect(ui->pushButton_2, &QPushButton::clicked, this, &MainWindow::on_pushButton_2_clicked);

    connect(udpScoket, &QUdpSocket::stateChanged, this, &MainWindow::slotSocketStateChanged);
    connect(udpScoket, &QUdpSocket::readyRead, this, &MainWindow::slotSocketReadyRead);

}


QString MainWindow::getLocalIp()
{
    QString hostName = QHostInfo::localHostName();//獲取本機主機名
    QHostInfo hostInfo = QHostInfo::fromName(hostName);  //返回主機名的IP地址

    QString localIP = "";
    QList<QHostAddress> addrList = hostInfo.addresses();   //主機IP地址列表

    if (!addrList.isEmpty())
    {
        for (int i = 0; i < addrList.size(); i++)
        {
            QHostAddress addr = addrList.at(i);
            if (QAbstractSocket::IPv4Protocol == addr.protocol())
            {
                localIP = addr.toString();
                break;
            }
        }
    }
    return localIP;
}


//綁定端口
void MainWindow::slotActBindPort()
{
    quint16 port=ui->spinBox->value();   //綁定本機UDp端口
    if(udpScoket->bind(port))
    {
        ui->textEdit->append(QStringLiteral("**已經綁定成功"));
        ui->textEdit->append(QStringLiteral("**綁定端口:")+QString::number(udpScoket->localPort()));
        ui->action->setEnabled(false); //開始綁定失效
        ui->action_2->setEnabled(true);//解除綁定使能
    }
    else
        ui->textEdit->append(QStringLiteral("綁定失敗"));
}

//解除端口
void MainWindow::slotActUnbindPort()
{

    udpScoket->abort();//解除綁定
    ui->action->setEnabled(true); //開始綁定失效
    ui->action_2->setEnabled(false);//解除綁定使能
    ui->textEdit->append(QStringLiteral("**已經解除綁定"));

}

//清空文本框
void MainWindow::slotActClearText()
{
    ui->textEdit->clear();
}


//退出
void MainWindow::slotActQuit()
{
    QMessageBox::StandardButton button = QMessageBox::question(this, "", QStringLiteral("是否要退出?"));
    if (button == QMessageBox::StandardButton::Yes)
        this->close();
}

//讀取socket傳入的數據
void MainWindow::slotSocketReadyRead()
{
    while(udpScoket->hasPendingDatagrams()) //當有數據傳入數據報
     {
       QByteArray  datagtam;
       datagtam.resize(udpScoket->pendingDatagramSize());//讀取數據報大小

       QHostAddress peerAddr;  //在已連接的狀態(tài)下,返回對方的socket的地址
       quint16 peerPort;       //在已連接的狀態(tài)下,返回對方的socket的端口

       udpScoket->readDatagram(datagtam.data(),datagtam.size(),&peerAddr,&peerPort);//讀取數據報的內容
       //qint64 readDatagram(char *data, qint64 maxlen, QHostAddress *host = nullptr, quint16 *port = nullptr);

       QString str=datagtam.data();
       QString  peer="[From "+peerAddr.toString()+":"+QString::number(peerPort)+"]";
       ui->textEdit->append( peer + str);
     }
}

 //狀態(tài)欄顯示Socket變化情況
void MainWindow::slotSocketStateChanged(QAbstractSocket::SocketState socketState)
{
    switch (socketState)
    {
            case QAbstractSocket::UnconnectedState: labstateScoket->setText(QStringLiteral("socket狀態(tài):UnconnectedState")); break;
            case QAbstractSocket::HostLookupState: labstateScoket->setText(QStringLiteral("socket狀態(tài):HostLookupState")); break;
            case QAbstractSocket::ConnectingState: labstateScoket->setText(QStringLiteral("socket狀態(tài):ConnectingState")); break;
            case QAbstractSocket::ConnectedState: labstateScoket->setText(QStringLiteral("socket狀態(tài):ConnectedState")); break;
            case QAbstractSocket::BoundState: labstateScoket->setText(QStringLiteral("socket狀態(tài):BoundState")); break;
            case QAbstractSocket::ClosingState: labstateScoket->setText(QStringLiteral("socket狀態(tài):ClosingState")); break;
            default: break;
     }

}


//發(fā)送信息
void MainWindow::on_pushButton_clicked()
{
        QString msg = ui->lineEdit->text(); //發(fā)送信息
        QByteArray str = msg.toUtf8();

        QString targetIp = ui->comboBox->currentText();  //目標IP就是主機地址的ip
        QHostAddress targetAddr(targetIp);
        quint16 targetPort = ui->spinBox_2->value();  //目標端口

        udpScoket->writeDatagram(str, targetAddr, targetPort);//發(fā)出數據報
        ui->textEdit->append("[out] " + msg);
        ui->lineEdit->clear();
        ui->lineEdit->setFocus();

}
//廣播信息
void MainWindow::on_pushButton_2_clicked()
{
      quint16 targetPort = ui->spinBox_2->value();  //目標端口
      QString msg=ui->lineEdit->text();

      QByteArray str = msg.toUtf8();
      udpScoket->writeDatagram(str, QHostAddress::Broadcast, targetPort);//發(fā)出數據報
      ui->textEdit->append("[broadcast] " + msg);
      ui->lineEdit->clear();
      ui->lineEdit->setFocus();

}

代碼化:

.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QAction>
#include <QComboBox>
#include <QGridLayout>
#include <QHBoxLayout>
#include <QHostInfo>
#include <QLabel>
#include <QLineEdit>
#include <QMainWindow>
#include <QMessageBox>
#include <QPlainTextEdit>
#include <QPushButton>
#include <QSpinBox>
#include <QUdpSocket>
#include <QVBoxLayout>

namespace Ui {
    class MainWindow;
}

class MainWindow : public QMainWindow {
    Q_OBJECT

public:
    explicit MainWindow(QWidget* parent = 0);
    ~MainWindow();

private slots:
    void slotActBindPort();
    void slotActUnbindPort();
    void slotActClearText();
    void slotActQuit();
    void slotSocketStateChanged(QAbstractSocket::SocketState socketState);
    void slotBtnSend();
    void slotBtnBroad();
    void slotSocketReadyRead();  //讀取socket傳入的數據

private:
    Ui::MainWindow* ui;

    QAction* m_pActBindPort;
    QAction* m_pActUnbindPort;
    QAction* m_pActClearText;
    QAction* m_pActQuit;
    QWidget* m_pCentralWidget;
    QLabel* m_pLabBindPort;
    QLabel* m_PLabTargetAddr;
    QLabel* m_pLabTargetPort;
    QSpinBox* m_pSpinBindPort;
    QComboBox* m_pComboTargetAddr;
    QSpinBox* m_pSpinTargetPort;
    QLineEdit* m_pLineEdit;
    QPushButton* m_pBtnSend;
    QPushButton* m_pBtnBroad;
    QPlainTextEdit* m_pPlainText;
    QLabel* m_pLabState;
    QUdpSocket* m_pUdpSocket;

    QString getLocalIP();
};

#endif  // MAINWINDOW_H

.cpp

#include "mainwindow.h"
#include <QToolBar>
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent), ui(new Ui::MainWindow) {
    ui->setupUi(this);
    //this->setWindowIcon(QIcon(":/new/prefix1/res/TitleIcon.png"));
    this->setWindowTitle(QStringLiteral("UDP Send/Receiver"));

    //工具欄
    ui->toolBar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
    m_pActBindPort = new QAction(QIcon(":/new/Check.png"), QStringLiteral("綁定端口"), this);
    m_pActUnbindPort = new QAction(QIcon(":/new/Break.png"), QStringLiteral("結束綁定"), this);
    m_pActClearText = new QAction(QIcon(":/new/remove.png"), QStringLiteral("清空文本"), this);
    m_pActQuit = new QAction(QIcon(":/new/back.png"), QStringLiteral("退出"), this);
    ui->toolBar->addAction(m_pActBindPort);
    ui->toolBar->addAction(m_pActUnbindPort);
    ui->toolBar->addSeparator();
    ui->toolBar->addAction(m_pActClearText);
    ui->toolBar->addSeparator();
    ui->toolBar->addAction(m_pActQuit);

    //界面布局
    m_pCentralWidget = new QWidget(this);

    QHBoxLayout* HLay1 = new QHBoxLayout;
    m_pLabBindPort = new QLabel(QStringLiteral("綁定端口"), m_pCentralWidget);
    m_pSpinBindPort = new QSpinBox(m_pCentralWidget);
    m_pSpinBindPort->setMinimum(1);
    m_pSpinBindPort->setMaximum(65535);
    m_pSpinBindPort->setValue(3200);
    m_PLabTargetAddr = new QLabel(QStringLiteral("目標地址"), m_pCentralWidget);
    m_pComboTargetAddr = new QComboBox(m_pCentralWidget);
    m_pLabTargetPort = new QLabel(QStringLiteral("目標端口"), m_pCentralWidget);
    m_pSpinTargetPort = new QSpinBox(m_pCentralWidget);
    m_pSpinTargetPort->setMinimum(1);
    m_pSpinTargetPort->setMaximum(65535);
    m_pSpinTargetPort->setValue(1600);
    HLay1->addWidget(m_pLabBindPort, 1, Qt::AlignRight);
    HLay1->addWidget(m_pSpinBindPort, 2);
    HLay1->addWidget(m_PLabTargetAddr, 1, Qt::AlignRight);
    HLay1->addWidget(m_pComboTargetAddr, 4);
    HLay1->addWidget(m_pLabTargetPort, 1, Qt::AlignRight);
    HLay1->addWidget(m_pSpinTargetPort, 2);

    QHBoxLayout* HLay2 = new QHBoxLayout;
    m_pLineEdit = new QLineEdit(m_pCentralWidget);
    m_pBtnSend = new QPushButton(QStringLiteral("發(fā)送消息"), m_pCentralWidget);
    m_pBtnBroad = new QPushButton(QStringLiteral("廣播消息"), m_pCentralWidget);
    HLay2->addWidget(m_pLineEdit);
    HLay2->addWidget(m_pBtnSend);
    HLay2->addWidget(m_pBtnBroad);

    QVBoxLayout* VLay = new QVBoxLayout(m_pCentralWidget);  //主布局必須設置parent,否則不會顯示布局
    // QVBoxLayout* VLay = new QVBoxLayout();
    VLay->addLayout(HLay1);
    VLay->addLayout(HLay2);
    m_pPlainText = new QPlainTextEdit(m_pCentralWidget);
    VLay->addWidget(m_pPlainText);

    this->setCentralWidget(m_pCentralWidget);
    this->setLayout(VLay);  //設置為窗體的主布。在指定了主布局的parent之后,這句話可有可無

    QString localIP = getLocalIP();
    this->setWindowTitle(this->windowTitle() + "---IP:" + localIP);
    m_pComboTargetAddr->addItem(localIP);
    m_pUdpSocket = new QUdpSocket(this);

    //狀態(tài)欄
    m_pLabState = new QLabel(QStringLiteral("socket狀態(tài):"), this);
    m_pLabState->setMinimumWidth(150);
    ui->statusbar->addWidget(m_pLabState);

    // connect
    connect(m_pActBindPort, &QAction::triggered, this, &MainWindow::slotActBindPort);
    connect(m_pActUnbindPort, &QAction::triggered, this, &MainWindow::slotActUnbindPort);
    connect(m_pActClearText, &QAction::triggered, this, &MainWindow::slotActClearText);
    connect(m_pActQuit, &QAction::triggered, this, &MainWindow::slotActQuit);
    connect(m_pBtnSend, &QPushButton::clicked, this, &MainWindow::slotBtnSend);
    connect(m_pBtnBroad, &QPushButton::clicked, this, &MainWindow::slotBtnBroad);
    connect(m_pUdpSocket, &QUdpSocket::stateChanged, this, &MainWindow::slotSocketStateChanged);
    connect(m_pUdpSocket, &QUdpSocket::readyRead, this, &MainWindow::slotSocketReadyRead);
}

MainWindow::~MainWindow() {
    //m_pUdpSocket->abort();
    //delete m_pUdpSocket;
    //m_pUdpSocket = nullptr;
    delete ui;
}

void MainWindow::slotActBindPort()
{
    quint16 port = m_pSpinBindPort->value();  //本機UDP端口
    if (m_pUdpSocket->bind(port)) {
        m_pPlainText->appendPlainText(QStringLiteral("**已成功綁定"));
        m_pPlainText->appendPlainText(QStringLiteral("綁定端口:") + QString::number(m_pUdpSocket->localPort()));

        //使能
        m_pActBindPort->setEnabled(false);
        m_pActUnbindPort->setEnabled(true);
    } else {
        m_pPlainText->appendPlainText(QStringLiteral("綁定失敗"));
    }
}

void MainWindow::slotActUnbindPort() {
    m_pUdpSocket->abort();  //解除綁定
    m_pPlainText->appendPlainText(QStringLiteral("**已解除綁定"));

    m_pActBindPort->setEnabled(true);
    m_pActUnbindPort->setEnabled(false);
}

void MainWindow::slotActClearText() { m_pPlainText->clear(); }

void MainWindow::slotActQuit() {
    QMessageBox::StandardButton button = QMessageBox::question(this, "", QStringLiteral("是否要退出?"));
    if (button == QMessageBox::StandardButton::Yes)
        this->close();
}

void MainWindow::slotSocketStateChanged(QAbstractSocket::SocketState socketState) {
    switch (socketState)
    {
            case QAbstractSocket::UnconnectedState: m_pLabState->setText(QStringLiteral("socket狀態(tài):UnconnectedState")); break;
            case QAbstractSocket::HostLookupState: m_pLabState->setText(QStringLiteral("socket狀態(tài):HostLookupState")); break;
            case QAbstractSocket::ConnectingState: m_pLabState->setText(QStringLiteral("socket狀態(tài):ConnectingState")); break;
            case QAbstractSocket::ConnectedState: m_pLabState->setText(QStringLiteral("socket狀態(tài):ConnectedState")); break;
            case QAbstractSocket::BoundState: m_pLabState->setText(QStringLiteral("socket狀態(tài):BoundState")); break;
            case QAbstractSocket::ClosingState: m_pLabState->setText(QStringLiteral("socket狀態(tài):ClosingState")); break;
            default: break;
     }

}

void MainWindow::slotBtnSend()
{
    QString msg = m_pLineEdit->text();
    QByteArray str = msg.toUtf8();
    QString targetIp = m_pComboTargetAddr->currentText();  //目標IP
    QHostAddress targetAddr(targetIp);
    quint16 targetPort = m_pSpinTargetPort->value();  //目標端口
    m_pUdpSocket->writeDatagram(str, targetAddr, targetPort);
    m_pPlainText->appendPlainText("[out] " + msg);
    m_pLineEdit->clear();
    m_pLineEdit->setFocus();

}

void MainWindow::slotBtnBroad()
{
    QString msg = m_pLineEdit->text();
    QByteArray str = msg.toUtf8();
    quint16 targetPort = m_pSpinTargetPort->value();
    m_pUdpSocket->writeDatagram(str, QHostAddress::Broadcast, targetPort);
    m_pPlainText->appendPlainText("[out] " + msg);
    m_pLineEdit->clear();
    m_pLineEdit->setFocus();



}

void MainWindow::slotSocketReadyRead()
{
    while (m_pUdpSocket->hasPendingDatagrams())
    {
        QByteArray dataGram;
        dataGram.resize(m_pUdpSocket->pendingDatagramSize());
        QHostAddress peerAddress;
        quint16 peerPort;
        m_pUdpSocket->readDatagram(dataGram.data(), dataGram.size(), &peerAddress, &peerPort);
        QString str = dataGram.data();
        QString peer = "[From " + peerAddress.toString() + ":" + QString::number(peerPort) + "]";
        m_pPlainText->appendPlainText(peer + str);
    }
}

QString MainWindow::getLocalIP() {
    QString hostName = QHostInfo::localHostName();
    QHostInfo hostInfo = QHostInfo::fromName(hostName);
    QString localIP = "";
    QList<QHostAddress> addrList = hostInfo.addresses();
    if (!addrList.isEmpty()) {
        for (int i = 0; i < addrList.size(); i++) {
            QHostAddress addr = addrList.at(i);
            if (QAbstractSocket::IPv4Protocol == addr.protocol()) {
                localIP = addr.toString();
                break;
            }
        }
    }
    return localIP;
}

結果:?

Qt —UDP通信QUdpSocket 簡介 +案例,qt,udp,開發(fā)語言

?發(fā)現自己用UI設計時,發(fā)送信息總會出現兩個發(fā)送信號,并且有一個是空白的,暫時還沒有找到問題所在之處,嚶嚶嚶~(/≧▽≦)/

5. UDP組播代碼示例

5.1 組播的特性

組播報文的目的地址使用D類IP地址,D類地址不能出現在IP報文的地址字段。用同一個IP多播地址接收多播數據報的所有主機構成一個組,稱為多播組(或組播組)。所有的信息接收者都加入一個組內,并且一旦加入后,流向組地址的數據報立即開始向接收者傳輸,組中的所有的成員都能接收到數據報。組中的成員是動態(tài)的,主機可以在任何人時間加入和離開組。

關于組播IP地址,有以下約定:

224.0.0.0 ~ 224.0.0.255? ?為預留的組播地址(永久組地址),地址224.0.0.0保留不做分配,其他地址供路由協議使用。
224.0.1.0 ~ 224.0.1.255? ?是公用組播地址,可以用于Internet。
224.0.2.0 ~ 238.255.255.255? ? ?為用戶可用的組播地址(臨時組地址),全網范圍內有效。
239.0.0.0 ~ 239.255.255.255? ? ?為本地管理組播地址,僅在特定的本地范圍內有效。所以,若是在家庭或辦公室局域網內測試UDP組播功能,可以使用這些IP。
原文鏈接:https://blog.csdn.net/WL0616/article/details/129050373

常量定義

描述

QUdpSocket::ShareAddress

0x1

1、允許其他服務綁定同樣的地址和端口
2、當多進程通過監(jiān)聽同一地址和端口,進而共享單個服務的負載時,將十分有用(例如:一個擁有幾個預先建立的監(jiān)聽者的WEB服務器能夠改善響應時間)。不過,由于任何服務都允許重新綁定(rebind),該選項應該引起某些安全上的考慮
3、需要注意的是,把該選項和ReuseAddressHint結合,也會允許你的服務重新綁定一個已存在的共享地址
4、在Unix上,該選項等同于SO_REUSEADDR;在Windows上,該選項被忽略

QUdpSocket::DontShareAddress

0x2

1、采用專有的方式綁定某個地址和端口,其他任何服務都不能再重新綁定

2、通過該選項,確保綁定成功,指定的服務將是地址和端口唯一監(jiān)聽者,就算是擁有ReuseAddressHint的服務也不允許重新綁定

3、在安全性上,該選項優(yōu)于ShareAddress,但是在某些操作系統上需要管理員的權限才能運行

4、在Unix和Mac OS上,綁定地址和端口的默認行為是非共享,所以該選項會被忽略;在Windows上,等同于SO_EXCLUSIVEADDRUSE套接字選項

QUdpSocket::ReuseAddressHint

0x4

1、為QUdpSocke提供提示,即在地址和端口已經被其他套接字綁定的情況下,也應該試著重新綁定

2、在Unix上,該選項被忽略;在Windows上等同于SO_REUSEADDR 套接字選項

QUdpSocket::DefaultForPlatform

0x0

1、當前平臺的默認選項

2、在Unix和Mac OS上,該選項等同于DontShareAddress + ReuseAddressHint;在Windows上等同于ShareAddress

5.2主要程序?

.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QAction>
#include <QComboBox>
#include <QHBoxLayout>
#include <QHostInfo>
#include <QLabel>
#include <QLineEdit>
#include <QMainWindow>
#include <QMessageBox>
#include <QPlainTextEdit>
#include <QPushButton>
#include <QRegExp>
#include <QSpinBox>
#include <QUdpSocket>
#include <QVBoxLayout>

namespace Ui {
    class MainWindow;
}

class MainWindow : public QMainWindow {
    Q_OBJECT

public:
    explicit MainWindow(QWidget* parent = 0);
    ~MainWindow();

private slots:
    void slotActJoinMulti();
    void slotActLeaveMulti();
    void slotActClearText();
    void slotActQuit();
    void slotSocketStateChanged(QAbstractSocket::SocketState socketState);
    void slotBtnMultiMsg();
    void slotReadyRead();

private:
    Ui::MainWindow* ui;

    QAction* m_pActJoinMulti;
    QAction* m_pActLeaveMulti;
    QAction* m_pActClearText;
    QAction* m_pActQuit;
    QWidget* m_pCentralWidget;
    QLabel* m_pLabPort;
    QLabel* m_pLabAddr;
    QSpinBox* m_pSpinPort;
    QComboBox* m_pComboAddr;
    QLineEdit* m_pLineEdit;
    QPushButton* m_pBtnSendMulti;
    QPlainTextEdit* m_pPlainText;
    QLabel* m_pLabState;
    QUdpSocket* m_pUdpSocket;
    QHostAddress m_multicastAddr;

    QString getLocalIP();
};

#endif  // MAINWINDOW_H

.cpp

#include "mainwindow.h"

#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent), ui(new Ui::MainWindow) {
    ui->setupUi(this);
    this->setWindowTitle(QStringLiteral("UDP Multicast"));

    //工具欄
    ui->mainToolBar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
    m_pActJoinMulti = new QAction(QIcon(":/new/prefix1/res/添加群組.png"), QStringLiteral("加入組播"), this);
    m_pActLeaveMulti = new QAction(QIcon(":/new/prefix1/res/退出群組.png"), QStringLiteral("退出組播"), this);
    m_pActClearText = new QAction(QIcon(":/new/prefix1/res/清空.png"), QStringLiteral("清空文本"), this);
    m_pActQuit = new QAction(QIcon(":/new/prefix1/res/退出.png"), QStringLiteral("退出"), this);
    ui->mainToolBar->addAction(m_pActJoinMulti);
    ui->mainToolBar->addAction(m_pActLeaveMulti);
    ui->mainToolBar->addSeparator();
    ui->mainToolBar->addAction(m_pActClearText);
    ui->mainToolBar->addSeparator();
    ui->mainToolBar->addAction(m_pActQuit);

    //界面布局
    m_pCentralWidget = new QWidget(this);
    m_pLabPort = new QLabel(QStringLiteral("組播端口"), m_pCentralWidget);
    m_pSpinPort = new QSpinBox(m_pCentralWidget);
    m_pSpinPort->setMinimum(1);
    m_pSpinPort->setMaximum(65535);
    m_pSpinPort->setValue(3200);
    m_pLabAddr = new QLabel(QStringLiteral("組播地址"), m_pCentralWidget);
    m_pComboAddr = new QComboBox(m_pCentralWidget);
    m_pComboAddr->setEditable(true);  //下拉框可編輯輸入
    m_pComboAddr->addItem("239.0.0.1");
    // 正則匹配 D類IP:224.0.0.0~239.255.255.255
    // .必須使用轉義字符\,否則.會匹配任意字符
    // C++中"\"在字符串中表示要用"\\"
    // 是 - 不是 ~ ; 是[0-9]不是[0~9]
    QRegExp regExp("^(22[4-9]|23[0-9])(\\.((\\d)|([1-9]\\d)|(1\\d{2})|(2[0-4]\\d)|(25[0-5]))){3}$");
    QValidator* pValidator = new QRegExpValidator(regExp, this);
    m_pComboAddr->setValidator(pValidator);
    QHBoxLayout* HLay1 = new QHBoxLayout();
    HLay1->addWidget(m_pLabPort, 1, Qt::AlignRight);
    HLay1->addWidget(m_pSpinPort, 1);
    HLay1->addWidget(m_pLabAddr, 1, Qt::AlignRight);
    HLay1->addWidget(m_pComboAddr, 2);
    m_pLineEdit = new QLineEdit(m_pCentralWidget);
    m_pBtnSendMulti = new QPushButton(QStringLiteral("組播消息"), m_pCentralWidget);
    QHBoxLayout* HLay2 = new QHBoxLayout();
    HLay2->addWidget(m_pLineEdit, 4);
    HLay2->addWidget(m_pBtnSendMulti, 1);
    m_pPlainText = new QPlainTextEdit(m_pCentralWidget);
    QVBoxLayout* VLay = new QVBoxLayout(m_pCentralWidget);
    VLay->addLayout(HLay1);
    VLay->addLayout(HLay2);
    VLay->addWidget(m_pPlainText);
    this->setCentralWidget(m_pCentralWidget);
    this->setLayout(VLay);

    //狀態(tài)欄
    m_pLabState = new QLabel(QStringLiteral("socket狀態(tài):"), this);
    m_pLabState->setMinimumWidth(150);
    ui->statusBar->addWidget(m_pLabState);

    QString str = getLocalIP();
    this->setWindowTitle(this->windowTitle() + "---IP:" + str);

    m_pUdpSocket = new QUdpSocket(this);
    m_pUdpSocket->setSocketOption(QAbstractSocket::MulticastTtlOption, 1);

    // connect
    connect(m_pActJoinMulti, &QAction::triggered, this, &MainWindow::slotActJoinMulti);
    connect(m_pActLeaveMulti, &QAction::triggered, this, &MainWindow::slotActLeaveMulti);
    connect(m_pActClearText, &QAction::triggered, this, &MainWindow::slotActClearText);
    connect(m_pActQuit, &QAction::triggered, this, &MainWindow::slotActQuit);
    connect(m_pUdpSocket, &QUdpSocket::stateChanged, this, &MainWindow::slotSocketStateChanged);
    connect(m_pBtnSendMulti, &QPushButton::clicked, this, &MainWindow::slotBtnMultiMsg);
    connect(m_pUdpSocket, &QUdpSocket::readyRead, this, &MainWindow::slotReadyRead);
}

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

void MainWindow::slotActJoinMulti() {
    QString ip = m_pComboAddr->currentText();
    m_multicastAddr = QHostAddress(ip);
    quint16 multicastPort = m_pSpinPort->value();
    if (m_pUdpSocket->bind(QHostAddress::AnyIPv4, multicastPort, QUdpSocket::ShareAddress)) {
        m_pUdpSocket->joinMulticastGroup(m_multicastAddr);  //加入多播組
        m_pPlainText->appendPlainText("**加入組播成功");
        m_pPlainText->appendPlainText("**組播地址IP:" + ip);
        m_pPlainText->appendPlainText("**綁定端口:" + QString::number(multicastPort));
        m_pActJoinMulti->setEnabled(false);
        m_pActLeaveMulti->setEnabled(true);
        m_pComboAddr->setEditable(false);
    } else {
        m_pPlainText->appendPlainText("**綁定端口失敗");
    }
}

void MainWindow::slotActLeaveMulti() {
    m_pUdpSocket->leaveMulticastGroup(m_multicastAddr);  //退出組播
    m_pUdpSocket->abort();                               //解除綁定
    m_pActJoinMulti->setEnabled(true);
    m_pActLeaveMulti->setEnabled(false);
    m_pComboAddr->setEnabled(true);
    m_pComboAddr->setEditable(true);
    m_pPlainText->appendPlainText("**已退出組播,解除端口綁定");
}

void MainWindow::slotActClearText() { m_pPlainText->clear(); }

void MainWindow::slotActQuit() {
    QMessageBox::StandardButton button = QMessageBox::question(this, "", "是否退出?");
    if (QMessageBox::StandardButton::Yes == button) {
        this->close();
    }
}

void MainWindow::slotSocketStateChanged(QAbstractSocket::SocketState socketState) {
    // case并不包含所有的情況,因為沒有寫listening的情況,所以就需要寫default
    switch (socketState) {
        case QAbstractSocket::UnconnectedState: m_pLabState->setText("socket狀態(tài):UnconnectedState"); break;
        case QAbstractSocket::HostLookupState: m_pLabState->setText("socket狀態(tài):HostLookupState"); break;
        case QAbstractSocket::ConnectingState: m_pLabState->setText("socket狀態(tài):ConnectingState"); break;
        case QAbstractSocket::ConnectedState: m_pLabState->setText("socket狀態(tài):ConnectedState"); break;
        case QAbstractSocket::BoundState: m_pLabState->setText("socket狀態(tài):BoundState"); break;
        case QAbstractSocket::ClosingState: m_pLabState->setText("socket狀態(tài):ClosingState"); break;
        default: break;
    }
}

void MainWindow::slotBtnMultiMsg() {
    QString msg = m_pLineEdit->text();
    QByteArray str = msg.toUtf8();
    quint16 multiPort = m_pSpinPort->value();
    m_pUdpSocket->writeDatagram(str, m_multicastAddr, multiPort);
    m_pPlainText->appendPlainText("[multicast] " + msg);
    m_pLineEdit->clear();
    m_pLineEdit->setFocus();
}

void MainWindow::slotReadyRead() {
    while (m_pUdpSocket->hasPendingDatagrams()) {
        QByteArray dataGram;
        dataGram.resize(m_pUdpSocket->pendingDatagramSize());
        QHostAddress peerAddr;
        quint16 peerPort;
        m_pUdpSocket->readDatagram(dataGram.data(), dataGram.size(), &peerAddr, &peerPort);
        QString str = dataGram.data();
        QString peer = "[From " + peerAddr.toString() + ":" + QString::number(peerPort) + "] ";
        m_pPlainText->appendPlainText(peer + str);
        qDebug() << m_pUdpSocket->peerAddress();
        qDebug() << m_pUdpSocket->localAddress().toString();
        qDebug() << m_pUdpSocket->localPort();
    }
}

QString MainWindow::getLocalIP() {
    QString localName = QHostInfo::localHostName();
    QHostInfo hostInfo = QHostInfo::fromName(localName);
    QList<QHostAddress> addrList = hostInfo.addresses();
    QString localIP = "";
    if (!addrList.isEmpty()) {
        for (int i = 0; i < addrList.size(); i++) {
            QHostAddress addr = addrList.at(i);
            if (QAbstractSocket::IPv4Protocol == addr.protocol()) {
                localIP = addr.toString();
                break;
            }
        }
    }
    return localIP;
}

結果:?

Qt —UDP通信QUdpSocket 簡介 +案例,qt,udp,開發(fā)語言

原文鏈接:https://blog.csdn.net/WL0616/article/details/129050373?文章來源地址http://www.zghlxwxcb.cn/news/detail-690583.html

到了這里,關于Qt —UDP通信QUdpSocket 簡介 +案例的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。如若轉載,請注明出處: 如若內容造成侵權/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經查實,立即刪除!

領支付寶紅包贊助服務器費用

相關文章

  • QT實現UDP通信

    QT實現UDP通信

    一、UDP簡介 1)UDP(User Datagram Protocol,用戶數據報協議) UDP是一個輕量級、不可靠、面向數據報的、無連接的傳輸層協議,多用于可靠性要求不嚴格,不是非常重要的傳輸,如直播、視頻會議等等。 2)Qt中QUdpSocket類繼承自QAbstractSocket,用來發(fā)送和接收UDP數據報,”Socket”即套

    2024年02月11日
    瀏覽(18)
  • Qt通信TCP/UDP

    qt socket通信,QTcpServer,QTcpSocket,QUdpSocket 鏈接2 鏈接3 鏈接4 QT中不再用套接字進行通信,而是使用連接對

    2024年02月09日
    瀏覽(19)
  • Qt 利用UDP進行通信

    UDP(用戶數據報協議)是一種簡單輕量級、不可靠、面向數據報,無連接的傳輸層協議。而TCP/IP協議卻是有連接的 1、網絡數據大多為短消息 2、擁有大量客戶端 3、對數據安全性無特殊要求 4、網絡負擔非常重,但對響應速度要求高。 因為upd是無連接的,所以兩個通信設備之

    2024年02月03日
    瀏覽(19)
  • QT網絡通信-TCP、UDP通信

    時間記錄:2024/1/17 pro文件添加模塊network (1)創(chuàng)建TCP服務器對象 QTcpServer (2)為 QTcpServer 對象的 newConnection 信號綁定槽,用來監(jiān)聽TCP客戶端的新連接,有新的客戶端連接便會觸發(fā)此信號 (3)使用 nextPendingConnection 方法獲取連接的Tcp客戶端對象 QTcpSocket (4)為 QTcpSocket 的 r

    2024年01月18日
    瀏覽(30)
  • Qt 8. UDP客戶端通信

    Qt 8. UDP客戶端通信

    1. 代碼 2. 效果 以上代碼可以實現UDP收發(fā)功能。

    2024年02月13日
    瀏覽(22)
  • 【QT網絡編程】實現UDP協議通信

    【QT網絡編程】實現UDP協議通信

    Internet 協議集支持一個無連接的傳輸協議,該協議稱為用戶數據報協議(UDP,User Datagram Protocol)。UDP 為應用程序提供了 一種無需建立連接就可以發(fā)送封裝的 IP 數據包的方法 。RFC 768 描述了 UDP。 UDP協議根據消息傳送模式可以分為: 單播(Unicast)、組播(Multicast)和廣播(

    2024年02月02日
    瀏覽(26)
  • QT網絡編程TCP/UDP開發(fā)流程 制作網絡調試助手

    QT網絡編程TCP/UDP開發(fā)流程 制作網絡調試助手

    1、QT的網絡編程: TCP和UDP TCP編程需要用到倆個類: QTcpServer 和 QTcpSocket QTcpSocket類 提供了一個TCP套接字 QTcpSocket是QAbstractSocket的一個子類,它允許您建立TCP連接和傳輸數據流 注意:TCP套接字不能在QIODevice::Unbuffered模式下打開。 QTcpServer類 提供一個基于tcp的服務器 2. 這個類可以接

    2023年04月08日
    瀏覽(15)
  • Qt - UDP網絡編程

    Qt - UDP網絡編程

    UDP(User Datagram Protocol,用戶數據報協議) UDP是一個輕量級、不可靠、面向數據報的、無連接的協議,多用于可靠性要求不嚴格,不是非常重要的傳輸。 QUdpSocket類繼承自QAbstractSocket,用來發(fā)送和接收UDP數據報,”Socket”即套接字,套接字即IP地址+端口號。其中IP地址指定了網絡

    2024年04月22日
    瀏覽(22)
  • Qt-udp(組播)

    Qt-udp(組播)

    2024年02月11日
    瀏覽(16)
  • Qt實現UDP發(fā)送與接收操作

    目錄 一、為什么要寫這篇文章,因為我就是要另辟蹊徑,當然也是汲取了網上大咖們的經驗,盡量簡潔的進行總結 二、關于接收數據需的條件,需要綁定本地IP地址和端口號,可解釋為此時為服務器模式,遠端為客戶端模式,實現的代碼非常簡單幾行代碼可以搞定 三、數據

    2024年02月11日
    瀏覽(15)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領取紅包,優(yōu)惠每天領

二維碼1

領取紅包

二維碼2

領紅包