Qt实现UDP单播和组播功能

这篇具有很好参考价值的文章主要介绍了Qt实现UDP单播和组播功能。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、UDP单播、广播和组播的说明

UDP是不可靠、无连接的,所以划分为发送方和接收方更好理解 

1、单播

UDP是无连接的,进行单播通信时,只需要绑定接收方端口就行,发送方直接通过接收方的ip和绑定的端口进行通信。发送方可以绑定端口也可以不用绑定端口,不绑定端口的话,系统会随机分配端口。

对于多网卡来说,需要指定网卡,绑定一个网卡的ip。如果不进行显式的绑定操作,QUdpSocket 对象将会使用默认的绑定方式,自动选择一个可用的 ip 地址进行绑定。这种情况下,数据包可能通过任意一个可用的网络接口发送出去。

2、广播

对于只有1个网卡的主机来说,可以不用显示绑定ip,发送方直接发送广播就行,接收方绑定广播端口就行,这样才能看到收到的消息。 

对于多网卡来说,要指定唯一的网卡并且在广播前要绑定广播端口,ip可以不用绑定,系统分配任意一个ip ,相当于 QHostAddress::AnyIPv4。

3、组播 

对于只有1个网卡的主机来说,可以不用绑定ip,直接绑定端口后加入组播就行。系统分配任意一个ip ,相当于 QHostAddress::AnyIPv4。

对于多网卡来说,要指定唯一的网卡并且在加入组播前要绑定组播端口,ip可以不用绑定,系统分配任意一个ip ,相当于 QHostAddress::AnyIPv4。

注意:指定网卡不等于指定ip!!! 

1、使用 setMulticastInterface 方法可以指定一个明确的网卡,但并不意味着只有一个 IP 地址。一个网卡可以绑定多个 IP 地址,例如在同一台主机上同时存在有线网卡和无线网卡,它们可能都连接到同一局域网,并分别配置了不同的 IP 地址。此时,通过 setMulticastInterface 方法指定了一个明确的网卡后,并不确定使用哪个 IP 地址来进行组播通信。

如果需要确保使用特定的 IP 地址进行组播通信,则需要使用 bind 方法来将 QUdpSocket 对象绑定到具体的 IP 地址和端口上,这样每次进行组播通信时,都会使用该 IP 地址来发送和接收数据报文。 

2、使用 QHostAddress::AnyIPv4 参数可以将 QUdpSocket 对象绑定到本机的所有 IPv4 地址。这意味着,该 QUdpSocket 对象可以接收通过本机的任意一个 IPv4 地址发送到指定端口的数据包。

然而,需要注意的是,绑定到多个 IPv4 地址并不意味着可以同时从多个地址接收数据包。在任何给定的时刻,QUdpSocket 对象只能通过一个 IP 地址接收数据包。

当有多个 IPv4 地址可用时,QUdpSocket 对象会选择其中一个地址来接收数据包。这个选择通常由操作系统或网络栈决定,并且可能会受到各种因素的影响,例如网络接口的优先级、路由表等。

因此,使用 QHostAddress::AnyIPv4 参数可以让 QUdpSocket 对象绑定到本机的所有 IPv4 地址,但实际上它只能通过其中一个地址接收数据包。具体使用哪个地址取决于操作系统和网络环境。

二、遇到的UDP通信的问题参考

      关于QT UDP组播的几个问题https://blog.csdn.net/tom06/article/details/52163665?spm=1001.2014.3001.5506

UDP多播/组播通信,同一局域网下的两台机器通信接收不到数据https://blog.csdn.net/qq_43290013/article/details/117288296?spm=1001.2014.3001.5506

QT读取网卡列表多网卡绑定组播网卡https://blog.csdn.net/qq_30727593/article/details/127441711?spm=1001.2014.3001.5506

三、效果与代码

qt udp组播,qt,udp,开发语言文章来源地址https://www.toymoban.com/news/detail-848572.html

#include "widget.h"
#include "ui_widget.h"

/*注意的问题:
问题一:
udp在同一局域网通信,如果一台主机收不到消息,只能本机收发,可以指定网口,删除其他网卡(保留直连网卡),关闭防火墙等操作。

问题二:
使用了不同的套接字对象。单播通信使用的是socket对象,而组播通信使用的是groupSocket对象。
在单播通信成功后,如果你立即尝试进行组播通信,可能会导致问题,因为在组播通信之前,还需要解除socket对象的绑定,然后重新绑定到组播端口。
同样地,在组播通信成功后,如果要切换回单播通信,需要先解除groupSocket对象的绑定,然后重新绑定到单播端口。
*/

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

    //构造udp套接字
    socket = new QUdpSocket;
    groupSocket = new QUdpSocket;

    ifaceList=QNetworkInterface::allInterfaces();
    for(int i=0;i<ifaceList.count();i++)
    {
        QNetworkInterface var=ifaceList.at(i);
        ui->nifComboBox->addItem(var.humanReadableName());
        //        qDebug() << var.humanReadableName() << ":" << ifaceList.at(i);
    }

    //本地主机名
    QString hostName = QHostInfo::localHostName();

    //获取本机IP地址
    hostIp = QHostAddress(QHostAddress::LocalHost);

    QList<QHostAddress> list = QNetworkInterface::allAddresses();
    foreach (QHostAddress address, list) {
        if (address.protocol() == QAbstractSocket::IPv4Protocol && !address.isLoopback()) {
            qDebug() << "Local IP Address: " << address.toString();
            this->ui->ipBox->setText(address.toString());
            break;
        }
    }

    if (list.isEmpty()) {
        qDebug() << "No network interfaces found.";
    } else {
        qDebug() << "Local Loopback Address: " << QHostAddress::LocalHost;
    }

    //组播的数据的生存期,数据报没跨1个路由就会减1.表示多播数据报只能在同一路由下的局域网内传播
    groupSocket->setSocketOption(QAbstractSocket::MulticastTtlOption,1);

    //当socket读缓存有数据,会立即触发readyRead
    connect(socket, &QUdpSocket::readyRead, this, &Widget::recvData);
    connect(groupSocket, &QUdpSocket::readyRead, this, &Widget::groupRecvData);


}

Widget::~Widget()
{
    delete ui;
}
//单播接收消息
void Widget::recvData()
{
    char buf[1024] = {0};
    socket->readDatagram(buf, sizeof (buf), &addr, &port);

    // 使用正则表达式去掉前缀
    QRegularExpression re("^::ffff:");
    QString targetIpAddr = addr.toString();
    targetIpAddr = targetIpAddr.replace(re, "");

    ui->targetPortBox->setValue(port);
    ui->targetIpBox->setText(targetIpAddr);
    QString prefixText = addr.toString() + ":" + QString::number(port) + ":" ;
    prefixText = QString("<font color='blue'>%1</font>").arg(prefixText);
    ui->recvEdit->append(prefixText + QString(buf));
}

//绑定端口
void Widget::on_bindBtn_clicked()
{
    // 解除groupSocket的绑定
    groupSocket->abort();

    //本机UDP端口
    hostPort = ui->bindPortBox->value();
    if (socket->bind(hostPort)){//绑定监听端口成功
        ui->bindBtn->setDisabled(true);
        ui->recvEdit->append("***已成功绑定端口:"+QString::number(socket->localPort()));
    }else{
        ui->recvEdit->append("***绑定失败***");
    }
}

void Widget::on_sendBtn_clicked()
{
    socket->writeDatagram(ui->sendEdit->toPlainText().toLatin1(),QHostAddress(ui->targetIpBox->text()),ui->targetPortBox->text().toInt());
}

void Widget::on_disbindBtn_clicked()
{
    socket->abort(); //不能解除绑定
    ui->recvEdit->append("***已解除绑定***");
    ui->bindBtn->setDisabled(false);
    //    delete socket;
}

void Widget::on_clearRecvBtn_clicked()
{
    ui->recvEdit->clear();
}

void Widget::on_clearSendBtn_clicked()
{
    ui->sendEdit->clear();
}

//加入组播
void Widget::on_joinBtn_clicked()
{
    QString groupIp = ui->multiIpBox->text();
    groupAddr = QHostAddress(groupIp);

    groupPort = ui->mulPortBox->value();

    //    // 解除socket的绑定
    //    socket->abort();

    //加入组播之前,必须先绑定端口,端口为多播组统一的一个端口。
    if(groupSocket->bind(QHostAddress::AnyIPv4,groupPort,QUdpSocket::ShareAddress | QUdpSocket::ReuseAddressHint))
    {
        if(ui->nifComboBox->currentIndex() != 0){
            groupSocket->setMulticastInterface(ifaceList.at(ui->nifComboBox->currentIndex() - 1));
        }
        //加入组播
        groupSocket->joinMulticastGroup(groupAddr,ifaceList.at(ui->nifComboBox->currentIndex() - 1));
        ui->joinBtn->setDisabled(true);
        ui->recvEdit->append("**加入组播成功");
        ui->recvEdit->append("**当前网卡:"+ui->nifComboBox->currentText());
        ui->recvEdit->append("**组播IP: "+ groupIp);
        ui->recvEdit->append("**绑定端口: "+QString::number(groupPort));
    }
    else
    {
        ui->recvEdit->append("**绑定端口失败");
    }
}

void Widget::on_exitBtn_clicked()
{
    //退出组播
    groupSocket->leaveMulticastGroup(groupAddr);

    //解除绑定
    groupSocket->abort();
    ui->joinBtn->setDisabled(false);
    ui->recvEdit->append("**已退出组播");
}

void Widget::on_broadSendBtn_clicked()
{
    groupSocket->writeDatagram(ui->sendEdit->toPlainText().toUtf8(),groupAddr,groupPort);
}

//组播接收消息
void Widget::groupRecvData()
{
    char buf[1024] = {0};
    groupSocket->readDatagram(buf, sizeof (buf), &addr, &port);
    QString prefixText = addr.toString() + ":" + QString::number(port) + ":" ;
    prefixText = QString("<font color='blue'>%1</font>").arg(prefixText);
    ui->recvEdit->append(prefixText + QString(buf));
}

到了这里,关于Qt实现UDP单播和组播功能的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • C++实现udp分包和组包

    1、udp数据是怎么发送的 UDP(user datagram protocol,用户数据报协议)是无连接的,面向消息的。不会使用块的合并优化算法,由于UDP支持的是一对多的模式,所以接收端的skbuff(套接字缓冲区)采用了链式结构来记录每一个到达的UDP包,在每个UDP包中就有了消息头(消息来源地址

    2024年02月16日
    浏览(32)
  • QT实现UDP通信

    一、UDP简介 1)UDP(User Datagram Protocol,用户数据报协议) UDP是一个轻量级、不可靠、面向数据报的、无连接的传输层协议,多用于可靠性要求不严格,不是非常重要的传输,如直播、视频会议等等。 2)Qt中QUdpSocket类继承自QAbstractSocket,用来发送和接收UDP数据报,”Socket”即套

    2024年02月11日
    浏览(35)
  • Qt实现UDP发送与接收操作

    目录 一、为什么要写这篇文章,因为我就是要另辟蹊径,当然也是汲取了网上大咖们的经验,尽量简洁的进行总结 二、关于接收数据需的条件,需要绑定本地IP地址和端口号,可解释为此时为服务器模式,远端为客户端模式,实现的代码非常简单几行代码可以搞定 三、数据

    2024年02月11日
    浏览(56)
  • 【QT】TCP/UDP详解及实现

    TCP模型是一个常见的网络协议参考模型,也称为TCP/IP模型或互联网模型。它是指TCP/IP协议族中的一组协议,用于在计算机网络中进行数据通信。TCP模型由四个层次组成,分别是: 应用层(Application Layer): 应用层是最靠近用户的层次,为用户提供各种网络应用服务。 包括常

    2024年02月10日
    浏览(37)
  • 【QT网络编程】实现UDP协议通信

    Internet 协议集支持一个无连接的传输协议,该协议称为用户数据报协议(UDP,User Datagram Protocol)。UDP 为应用程序提供了 一种无需建立连接就可以发送封装的 IP 数据包的方法 。RFC 768 描述了 UDP。 UDP协议根据消息传送模式可以分为: 单播(Unicast)、组播(Multicast)和广播(

    2024年02月02日
    浏览(56)
  • Qt实现UDP高速通讯,下位机为FPGA

    目录 一、为什么要写这篇文章,因为我就是要另辟蹊径,当然也是汲取了网上大咖们的经验,尽量简洁的进行总结 二、关于接收数据需的条件,需要绑定本地IP地址和端口号,可解释为此时为服务器模式,远端为客户端模式,实现的代码非常简单几行代码可以搞定 三、数据

    2024年02月12日
    浏览(31)
  • [Qt网络编程]之UDP通讯的简单编程实现

    hello!欢迎大家来到我的Qt学习系列之 网络编程之UDP通讯的简单编程实现。 希望这篇文章能对你有所帮助!!! 本篇文章的相关知识请看我的上篇文章: 目录 UDP通讯  基于主窗口的实现  基于线程的实现          UDP数据报协议是一个面向无连接的传输层报文协议 ,它简

    2024年04月25日
    浏览(59)
  • QT网络编程之实现UDP广播发送和接收

    一.UDP广播介绍 UDP广播地址固定IP地址为:XXX.XXX.XXX.255。 如果向全网段发送广播消息,那么广播地址为:255.255.255.255; 如果向单个网段发送广播消息,例如你的IP是192.168.31.104,那么广播地址为192.168.31.255。 广播消息接收方需要绑定0.0.0.0地址并监听指定端口即可收到广播的群

    2024年03月25日
    浏览(67)
  • JavaCV音视频开发宝典:UDP局域网组播推流,多播推流,局域网多网段推流,使用UDP方式推送TS组播流,实现UDP一对多组播

    《JavaCV音视频开发宝典》专栏目录导航 《JavaCV音视频开发宝典》专栏介绍和目录 ​ 在之前文章中我们已经实现rtp点到点传输JavaCV音视频开发宝典:rtp点到点音视频传输(一对一音视频直播)和rtp广播JavaCV音视频开发宝典:rtp广播方式发送TS流音视频传输(一对多音视频会议

    2024年02月03日
    浏览(65)
  • Qt之UDP通信

    目录 一、UDP简介 二、QUdpSocket类 三、UDP服务器 四、UDP客户端 五、代码 1.udp服务端 2.udp客户端 UDP(User Datagram Protocol 即用户数据报协议)是一个轻量级的,不可靠的,面向数据 报的无连接协议 。由于 UDP 的特性:它不属于连接型协议,因而具有资源消耗小,处理速度快的优点

    2024年02月02日
    浏览(33)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包