当前位置: 首页 > article >正文

C++网络编程之多播

概述

        在移动互联网时代,随着多媒体应用的日益普及,如何高效地将数据传输给多个接收者成为了网络通信领域的一个重要课题。多播(英文为Multicast)作为一种高效的网络通信方式,可以将数据同时发送到多个接收者,而不需要为每个接收者单独建立连接。

        与单播(英文为Unicast)相比,多播减少了网络中的数据包复制,从而降低了带宽消耗。与广播(英文为Broadcast)相比,多播仅向那些明确表示希望接收数据的主机发送数据,而不是局域网内的所有主机。多播技术因其高效的数据传输特性,特别适合视频会议、在线教育、远程培训、直播服务等应用场景。

        在IPv4地址中,224.0.0.0至239.255.255.255被保留用于多播。IPv6则有更大的多播地址空间,从FF00::/8开始。

多播组

        多播不是直接面向特定主机的,而是面向一组主机。任何想要接收特定多播组数据的主机,都可以加入该组。当数据发送到一个特定的多播地址时,所有加入了这个多播组的主机都能接收到这些数据。多播组的成员身份是动态的,设备可以根据需要加入或离开多播组。

        1、加入多播组。要让设备能够接收多播数据,首先需要告诉网络层该设备希望加入某个多播组,这是通过设置套接字选项来实现的。

        (1)对于IPv4,使用setsockopt函数设置IP_ADD_MEMBERSHIP选项。

        (2)对于IPv6,使用setsockopt函数设置IPV6_JOIN_GROUP选项。

        具体如何加入,可参考下面的示例代码。

// 对于IPv4
struct ip_mreq mreq;
// 多播地址
mreq.imr_multiaddr.s_addr = inet_addr("224.0.0.1");
// 任意接口,也可指定某个特定接口
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
if (setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&mreq, sizeof(mreq)) < 0)
{
    cout << "加入多播组失败" << endl;
}

// 对于IPv6
struct ipv6_mreq mreq6;
// 多播地址
mreq6.ipv6mr_multiaddr = in6addr_any;
// 任意接口
mreq6.ipv6mr_interface = 0;
if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq6, sizeof(mreq6)) < 0)
{
    cout << "加入多播组失败" << endl;
}

        2、离开多播组。当不再需要接收多播数据时,设备可以离开多播组以释放资源。

        (1)对于IPv4,使用setsockopt函数设置IP_DROP_MEMBERSHIP选项。

        (2)对于IPv6,使用setsockopt函数设置IPV6_LEAVE_GROUP选项。

        具体如何离开,可参考下面的示例代码。

// 对于IPv4
if (setsockopt(sockfd, IPPROTO_IP, IP_DROP_MEMBERSHIP, (char *)&mreq, sizeof(mreq)) < 0)
{
    cout << "离开多播组失败" << endl;
}

// 对于IPv6
if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &mreq6, sizeof(mreq6)) < 0)
{
    cout << "离开多播组失败" << endl;
}

        3、成员资格查询。在某些情况下,我们可能需要查询一个网络接口是否已经加入了特定的多播组。

        (1)对于IPv4,使用setsockopt函数设置IP_MULTICAST_IF选项。

        (2)对于IPv6,使用setsockopt函数设置IPV6_MULTICAST_IF选项。

        具体如何查询,可参考下面的示例代码。

// 对于IPv4,查询成员资格
struct ip_mreqn mreqn;
socklen_t len = sizeof(mreqn);
if (getsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_IF, &mreqn, &len) < 0)
{
    cout << "获取多播接口失败" << endl;
}
else
{
    // 判断是否加入了多播组
    if (mreqn.mr_multiaddr.s_addr == INADDR_ANY)
    {
        cout << "没有加入任何多播组" << endl;
    }
    else
    {
        cout << "已加入多播组, 地址为: " << inet_ntoa(mreqn.mr_multiaddr) << endl;
    }
}

// 对于IPv6,查询成员资格
struct ipv6_mreq mreq6;
socklen_t len = sizeof(mreq6);
if (getsockopt(sockfd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &mreq6, &len) < 0)
{
    cout << "获取多播接口失败" << endl;
}
else
{
    // 判断是否加入了多播组
    if (memcmp(&mreq6.ipv6mr_multiaddr, &in6addr_any, sizeof(in6addr_any)) == 0)
    {
        cout << "没有加入任何多播组" << endl;
    }
    else
    {
        char pszAddr[INET6_ADDRSTRLEN];
        inet_ntop(AF_INET6, &mreq6.ipv6mr_multiaddr, pszAddr, sizeof(pszAddr));
        cout << "已加入多播组, 地址为: " << pszAddr << endl;
    }
}

收发数据

        发送多播数据与发送单播数据类似,只需要指定多播地址作为目标即可。根据多播的特性可以知道,发送方并不关心哪些主机实际上接收了数据。具体如何发送,可参考下面的示例代码。

// 设置多播地址
struct sockaddr_in dest;
dest.sin_family = AF_INET;
dest.sin_port = htons(PORT);
inet_pton(AF_INET, "224.0.0.1", &dest.sin_addr);

// 发送数据
const char *pszMsg = "Hello, Hope Wisdom";
sendto(sockfd, pszMsg, strlen(pszMsg), 0, (struct sockaddr *)&dest, sizeof(dest));

        接收多播数据同样与接收单播数据相似,但需要绑定到一个特定的端口,并且通常绑定到一个任意IP地址(INADDR_ANY)。这意味着,我们可以从任何网络接口接收数据。具体如何接收,可参考下面的示例代码。

struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(PORT);
addr.sin_addr.s_addr = INADDR_ANY;

// 绑定套接字到端口
bind(sockfd, (struct sockaddr *)&addr, sizeof(addr));

// 接收数据
char pszBuf[BUFSIZE] = {0};
int nRecvedBytes = recvfrom(sockfd, pszBuf, BUFSIZE, 0, NULL, NULL);
cout << "Recved data: " << pszBuf<< endl;


http://www.kler.cn/a/409802.html

相关文章:

  • 游戏引擎学习第22天
  • 蓝桥杯不知道叫什么题目
  • Macos远程连接Linux桌面教程;Ubuntu配置远程桌面;Mac端远程登陆Linux桌面;可能出现的问题
  • MyBatis基本使用
  • python-MatchObject对象方法
  • Gradio学习笔记记录
  • Js-函数-03
  • 【redis 】string类型详解
  • 工程化RAG-无法评估,就无法改进
  • 宝可梦GO如何超越李飞飞的空间智能?150万亿参数解锁现实边界 | LeetTalk Daily...
  • 新版布谷直播软件源码开发搭建功能更新明细
  • STM32 USART串口发送
  • 【Leetcode 每日一题】743. 网络延迟时间
  • Ant Design Vue中使用change方法时如何传递自定义参数
  • Lumos学习王佩丰Excel第十六讲:简单文本函数
  • 快速排序&Lambda表达式
  • 深度学习中的循环神经网络(RNN)与时间序列预测
  • 我的创作之路:机缘、收获、日常与未来的憧憬
  • 基础免杀 从.rsrc加载shellcode上线
  • 融合模型VotingRegressor 在线性数据上的比对与应用
  • Flutter 设计模式全面解析:抽象工厂
  • 3dm 格式详解,javascript加载导出3dm文件示例
  • Nginx防御机制
  • 数据结构——停车场管理问题
  • 致翔OA open_juese.aspx SQL注入致RCE漏洞复现
  • 算法分析 —— 《位运算基础》