多播与广播

Posted by KalosAner on January 22, 2025

一、引言

多播和广播都是向多个主机传递数据的方式,主要区别在于多播可以向多播组中的所有主机传递数据,广播可以向整个子网的所有主机传递数据。

二、多播

多播(Multicast)方式基于 UDP 传输数据。多播通信需要先建立多播组,加入该组的主机即可接收发往该多播组的数据。发送端只需要向多播组发送一次数据。每个多播组都有一个多播组 IP,多播组的 IP 属于 D 类 IP 地质(224.0.0.0~239.255.255.255)。

多播组通信方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 发送方
int send_sock;
int time_live = 64;
send_sock = socket(PF_INET, SOCK_DGRAM, 0);
setsockopt(send_sock, IPPROTO_IP, IP_MULTICAST_TTL, (void*) &time_live, sizeof(time_live));

// 接收方
int recv_sock;
struct ip_mreq join_adr;

recv_sock = socket(PF_INET, SOCK_DGRAM, 0);
join_adr.imr_multiaddr.s_addr="multicast IP";
join_adr.imr_interface.s_addr="host IP";
setsockopt(recv_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void*) &join_adr, sizeof(join_adr));

// ip_mreq 原型
struct ip_mreq {
    struct in_addr imr_multiaddr;
    struct in_addr imr_interfaces;
}

代码:news_sender.cnews_receiver.c

多播组成员信息存储

当一个进程加入某个多播组时,操作系统会在本机的网络协议栈种维护该信息,并通过 IGMP(Internet Group Management Protocol) 向局域网中的路由器通告自己加入了这个多播组。

交换机通常使用 IGMP Snooping 监听 IGMP 报文,确定哪些端口上有主机加入了哪些多播组从而决定哪些端口需要转发多播流量。

路由器会维护多播路由表(MRIB),使用协议如 PIM(Protocol Independent Multicast) 来确保多播数据包能被正确转发到多个接收者。

多播数据如何到达所有组成员

当发送数据向某个多播 IP 地址(如:239.1.1.1)时,数据包的 IP 目标地址是多播地址而不是主机 IP。

交换机如果启用了 IGMP Snooping,它只会向加入多播组的端口转发数据。

如果跨网段通信,路由器使用 PIM 或其他多播路由协议决定如何转发多播数据。

多播 IP 地址会被映射到一个以太网 MAC 地址,以太网网卡会对多播 MAC 地址进行监听。

与普通 UPD 数据报的区别

目标IP 地址:多播的 IP 地址是多播组地址

TTL:多播初始 TTL 被设置为较小的值表示仅在局域网传输。跨网段时,TTL 需手动设置更大值。

MAC 地址:单播 MAC 地址只有目标主机才能接收数据;多播 IP 地址会映射到组播 MAC 地址。

路由表:多播路由由多播路由协议控制,路由器维护多播转发表

多播组管理

在广域网或者互联网上,多播流量通常受到严格限制,需要路由器和 ISP 支持 PIM、MBGP 等协议,并且可能需要认证或者专门的网络配置。

假设两个不相关的进程在同一台设备或者同一个网络中加入了相同的多播组(例如239.1.1.1)会导致数据冲突。为了避免这种情况,可以使用不同的多播地址或者不同的端口(239.1.1.1:5000接收视频流,239.1.1.1:6000接收传感器数据),也可以进行消息过滤。

三、广播

广播分为两种:直接广播(特定子网广播),本地广播(当前子网广播)

直接广播目标 IP 地址为:192.12.34.255

本地广播目标 IP 地址为:255.255.255.255

使用广播必须对套接字进行设置,默认生成的套接字会阻止广播

1
2
3
4
5
// 发送方
int send_sock;
int bcast = 1;
send_socke = socket(PF_INET, SOCK_DGRAM, 0);
setsockopt(send_sock, SOL_SOCKET, SO_BROADCAST, (void*) &bcast, sizeof(bcast));

子网中的所有主机都必须接收广播信息。

代码:news_sender_brd.cnews_sender_win.c