QT socket UDP通信程序模板

現列出幾個概念:

①本地IP。對於運行在PC機上的程序,本地IP就是PC的IP,以windows爲例,直接在命令行中執行ipconfig命令,即可查到本機IP,如下圖:

②遠程IP。我們寫的程序要把數據發送到哪個IP的哪個端口上,這個IP就是指的遠端(遠程)IP

③端口號。本質上也屬於協議地址的一部分,可以認爲是某個IP下更細分的地址。可以這樣理解,IP代表了一棟樓的樓號,那麼端口號就代表了某棟樓中的某一門牌號,相當於端口號是一個更詳細的地址。

④bind函數。socket編程中常用的一個函數。在UDP通信中,需要接收數據的一端必須要用bind 函數。發送數據時,直接向遠端的【IP::端口】發即可,而接收數據時,需要監聽(或者叫綁定)【自己的IP:端口號】,而不是監聽別人的IP:端口號。UDP通信並不區分服務端和客戶端。

 

一個典型的應用場景:

在同一局域網中的兩臺PC,【電腦1】的IP爲192.168.2.61(我寫的QT程序就在這臺電腦上),【電腦2】的IP爲192.168.2.19(我在上面打開了一個網絡調試助手,sscom網上能下載到)。

【電腦2】上的sscom配置如下:

【電腦1】上自己寫的QT程序如下:

核心程序如下:
在pro文件中修改:

QT       += core gui network
//在頭文件中添加私有成員

    QUdpSocket *udpSocket;
    QString localIpStr;//記錄ui中用戶輸入的IP
    uint16_t localPort;
    QString remoteIpStr;
    uint16_t remotePort;
    QHostAddress localIp;//程序中IP都是QHostAddress類型的
    QHostAddress remoteIp;


//CPP如下

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

#include <qDebug>


MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    udpSocket = new QUdpSocket(this);
    connect(udpSocket,SIGNAL(readyRead()), this, SLOT(when_udp_readyRead()));//收到別的電腦發來的消息
}

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


void MainWindow::on_ptnSendRoute_clicked()//點擊該按鈕,可以遠端IP發送字符串數據
{
    char frame[] = "123456789";

    qint64 len = udpSocket->writeDatagram(frame, sizeof(frame), remoteIp, remotePort);
    if(len > 0)
        qDebug() << "send ok: " << len;
}

void MainWindow::on_ptnComm_clicked()
{
    bool ok;
    localIpStr = ui->lineEdit_localIp->text();
    localPort = ui->lineEdit_localPort->text().toInt(&ok);
    if(!ok) qDebug() << "你輸入的本地端口號有誤";
    remoteIpStr = ui->lineEdit_remoteIp->text();
    remotePort = ui->lineEdit_remotePort->text().toInt(&ok);
    if(!ok) qDebug() << "你輸入的遠程端口號有誤";

    if(!localIp.setAddress(localIpStr))
        qDebug() << "你輸入的本地IP有誤";

    if(!remoteIp.setAddress(remoteIpStr))
        qDebug() << "你輸入的遠程IP有誤";

    if(!udpSocket->bind(localIp, localPort))
        qDebug() << "無法監聽(bind)本地UDP端口:" << localIp << localPort;//解決方案見下文


}

void MainWindow::when_udp_readyRead()
{
    QByteArray datagram;
    datagram.resize(udpSocket->pendingDatagramSize());
    QHostAddress msgIp;
    uint16_t msgPort;
    udpSocket->readDatagram(datagram.data(), datagram.size(), &msgIp, &msgPort);
    qDebug() << "收到來自這個IP/PORT的消息:" << msgIp.toString() << msgPort;
    QString msg = datagram.data();
    qDebug() << "消息內容爲" << msg;
}

void MainWindow::on_ptnCloseComm_clicked()
{
    udpSocket->close();
    qDebug() << "已關閉,不再接收UDP消息";
}

點擊發送按鈕,即可在【電腦2】的sscom中看到數據。在SSCOM中發送數據,也可以在QT的debug窗口收到數據。

 

 

 

注意事項:程序中bind某個IP/PORT之後,再次調用bind會失敗,QT的debug窗口中會報錯:

QNativeSocketEngine::bind() was not called in QAbstractSocket::UnconnectedState

解決方法是,在bind之前,先關掉socket,在重開socket,代碼很簡單:

udpSocket->close();
udpSocket->open(QIODevice::ReadWrite);
if(!udpSocket->bind(localIp, localPort))
        qDebug() << "無法監聽本地UDP端口:" << localIp << localPort;

爲什麼要再次bind?其實這種需求很常見,比如用戶想修改監聽的端口號

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章