QT组播的建立和使用(绑定特定的网卡,绑定特定IP)

https://blog.csdn.net/only_write_bug/article/details/159115776?spm=1011.2415.3001.5331

目录

一、组播介绍

二、组播初始化和使用

1、创建QUdpSocket对象

2、绑定本地端口

3、加入组播组

4、发送组播数据

5、接收组播数据

6、离开组播组

三、为什么需要指定网卡,如何绑定固定网卡

1、如何查看自己电脑有那些网卡信息

2、如何查找自己电脑对应IP的网卡信息以及绑定


一、组播介绍

组播(Multicast)是一种高效的网络通信方式,它允许将数据包同时发送给一组特定的接收者,而无需为每个接收者都复制一份数据。

组播地址 :IPv4组播地址范围是 224.0.0.0 ~ 239.255.255.255(D类地址)。其中 224.0.0.0 ~ 224.0.0.255 为本地链路组播地址(如 224.0.0.1 表示所有子网主机),通常不被应用程序使用;239.0.0.0 ~ 239.255.255.255 为管理权限组播地址(私有组播地址),适合内部网络使用。

组播组:加入同一个组播地址的所有主机形成一个组播组。发送者只需将数据发往组播地址,路由器会负责将数据复制到有接收者的链路上。

相关链接:

https://blog.csdn.net/only_write_bug/article/details/159115776?spm=1011.2415.3001.5331

二、组播初始化和使用

1、创建QUdpSocket对象

cpp 复制代码
QUdpSocket *udpSocket = new QUdpSocket(this);

2、绑定本地端口

// ShareAddress :允许共享地址。如前所述,允许多个套接字绑定到同一地址和端口

// ReuseAddressHint: 提示地址重用。为套接字提供一个"提示",告诉它即使地址和端口正被另一个套接字使用,也应尝试重新绑定。

// ShareAddress和ReuseAddressHint通常一起使用

这里绑定到 QHostAddress::AnyIPv4 表示监听所有网络接口上的指定端口。如果希望只监听特定网卡,可以传入该网卡的IP地址。

cpp 复制代码
udpSocket->bind(QHostAddress::AnyIPv4, 12345, QUdpSocket::ShareAddress);

这里为绑定到特定IP地址和端口,selfip为QString对象,所以需要转换为QHostAddress。selfip和port为你需要绑定的ip和端口。

cpp 复制代码
if (!udpSocket->bind(QHostAddress(selfip), myport, QUdpSocket::ShareAddress | QUdpSocket::ReuseAddressHint)) {
        qWarning() << "Failed to bind status socket:" << m_socket->errorString();
    }

3、加入组播组

cpp 复制代码
QHostAddress multicastAddr("239.255.43.21");
udpSocket->joinMulticastGroup(multicastAddr);

多个网卡的情况下,你已知自己需要绑定的网卡名称,可直接绑定到对应网卡。如下:

cpp 复制代码
QNetworkInterface interface = QNetworkInterface::interfaceFromName("eth0");
udpSocket->joinMulticastGroup(multicastAddr, interface);

4、发送组播数据

发送方不需要加入组播组,只需将数据报的目的地址设为组播地址即可。发送前建议设置组播数据包的TTL(生存时间):

cpp 复制代码
udpSocket->setSocketOption(QAbstractSocket::MulticastTtlOption, 1); // TTL=1 限制在本地子网
udpSocket->writeDatagram(datagram.data(), datagram.size(), multicastAddr, 12345);

5、接收组播数据

当有数据到达绑定的端口时,QUdpSocket 会发出 readyRead() 信号,在槽函数中读取:

cpp 复制代码
connect(udpSocket, &QUdpSocket::readyRead, this, [=](){
    while (udpSocket->hasPendingDatagrams()) {
        QByteArray datagram;
        datagram.resize(udpSocket->pendingDatagramSize());
        QHostAddress sender;
        quint16 senderPort;
        udpSocket->readDatagram(datagram.data(), datagram.size(), &sender, &senderPort);
        // 处理数据或者定义信号将数据传到其他线程进行处理...
    }
});

6、离开组播组

当你的程序不再需要接收组播信息时,应该先离开组播组

cpp 复制代码
udpSocket->leaveMulticastGroup(multicastAddr);

三、为什么需要指定网卡,如何绑定固定网卡

当你调用udpSocket->bind(QHostAddress::AnyIPv4, 12345, QUdpSocket::ShareAddress);绑定任意IP信息时,如果你的电脑只有一个网卡的话问题不大,但是如果有多个网卡就会出现接收不到信息的问题,因为电脑组播在接收数据流的时候可能会切换到其他网卡接收,导致组播接收数据出现丢失,但是不会影响你的组播信息发送。

所以在电脑有多网卡或者有虚拟环境的时候,推荐组播绑定到特定的网卡。

1、如何查看自己电脑有那些网卡信息

添加<QNetworkInterface> <QNetworkDatagram>头文件之后,可调用QT的 QNetworkInterface::allInterfaces()查看目前你的电脑可用的所有网卡信息。如果你已知你的网卡信息就不需要。

cpp 复制代码
QString info = "<<<<<<<<Available network interfaces>>>>>>>>";
    qDebug()<<info;
    foreach (QNetworkInterface iface, QNetworkInterface::allInterfaces()) {
        if (iface.flags() & QNetworkInterface::IsUp &&
            iface.flags() & QNetworkInterface::IsRunning &&
            !(iface.flags() & QNetworkInterface::IsLoopBack)) {
            info = "  Interface:" + iface.name()
                   + "  Human readable:" + iface.humanReadableName();
            qDebug()<<info;
            foreach (QNetworkAddressEntry entry, iface.addressEntries()) {
                if (entry.ip().protocol() == QAbstractSocket::IPv4Protocol) {
                    info = "    IP:" + entry.ip().toString();
                    qDebug()<<info;
                }
            }
        }
    }

2、如何查找自己电脑对应IP的网卡信息以及绑定

self为自身IP信息。

cpp 复制代码
 QNetworkInterface   m_multicastIface;
if (!selfip.isEmpty()) 
{
        const auto interfaces = QNetworkInterface::allInterfaces();
        for (const QNetworkInterface &iface : interfaces) //遍历所有网卡信息
        {
            for (const QNetworkAddressEntry &entry : iface.addressEntries()) //遍历所有IP地址
            {
                if (entry.ip().toString() == selfip)//找到对应IP信息
                {
                    m_multicastIface = iface;
                    qDebug() << "找到匹配网卡:" << iface.humanReadableName() << "IP:" <<selfip;
                    break;
                }
            }
            if (m_multicastIface.isValid()) break;
        }
}

//加入组播组
if (m_multicastIface.isValid()) 
{
    if (m_socket->joinMulticastGroup(groupAddress, m_multicastIface)) 
    {
        qDebug() << "通过网卡" << m_multicastIface.humanReadableName() << "加入组播组成功";
        // 设置组播发送的接口(确保发送也走同一网卡) 可不设置
        udpsocket->setMulticastInterface(m_multicastIface);
     } else{
        qWarning() << "指定网卡加入组播组失败:" << udpsocket->errorString();
     }
 }
相关推荐
Ralph_Y2 小时前
C++:static
开发语言·c++
松☆2 小时前
C++ 程序设计基础:从 Hello World 到数据类型与 I/O 流的深度解析
c++·算法
小江的记录本2 小时前
【HTTP】HTTP请求方法与状态码(全体系知识总结+附表格)
前端·网络·后端·网络协议·http·状态模式·web
nimadan122 小时前
海螺AI漫剧2025推荐,解锁沉浸式互动叙事新体验
c++
今儿敲了吗2 小时前
41| 快速乘
数据结构·c++·笔记·学习·算法
愚者游世2 小时前
alignof 和 alignas各版本异同
c++·学习·程序人生·职场和发展·visual studio
ysa0510302 小时前
树的定向(dfs并查集贪心)
数据结构·c++·笔记·算法·深度优先·图论
是宇写的啊2 小时前
网络原理1
网络
懒洋洋在睡觉2 小时前
Vulkan demo入门教程三:逻辑设备、队列与交换链
c++·图形渲染