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?其实这种需求很常见,比如用户想修改监听的端口号

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