只有类型为 SOCK_DGRAM 和 SOCK_RAW 的 AF_INET6 和 AF_INET 套接字支持 IP 多播。IP 多播仅在接口驱动程序支持多播的子网中受到支持。
要发送多播数据报,请在 224.0.0.0 到 239.255.255.255 的范围中指定一个 IP 多播地址作为 sendto(3SOCKET) 调用的目标地址。
缺省情况下,发送 IP 多播数据报时其生存时间 (time-to-live, TTL) 值为 1。此值可以阻止将数据报转发到单个子网之外。使用套接字选项 IP_MULTICAST_TTL,可以将后续多播数据报的 TTL 设置为 0 到 255 之间的任何值。此功能用于控制多播的范围。
u_char ttl; setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL, &ttl,sizeof(ttl))
TTL 为 0 的多播数据报不能在任何子网中传输,但是在发送主机属于目标组并且发送套接字上未禁用多播回送的情况下可以进行本地传送。如果有一个或多个多播路由器连接到第一跃点子网,则 TTL 大于 1 的多播数据报可以传送到多个子网。为了提供有意义的范围控制,多播路由器支持 TTL 阈值概念。这些阈值会阻止低于特定 TTL 值的数据报遍历某些子网。这些阈值将针对具有以下初始 TTL 值的多播数据报强制实施相应约定:
限定在同一主机
限定在同一子网
限定在同一站点
限定在同一地区
限定在同一洲
范围不受限制
站点和地区并未严格定义,站点可以根据实际情况再分为更小的管理单元。
应用程序可以选择以上列出的 TTL 值以外的初始 TTL 值。例如,应用程序可以通过发送多播查询来对网络资源执行扩展环搜索,即第一个 TTL 值为 0,然后逐渐增大 TTL 的值,直到收到回复为止。
多播路由器不转发任何目标地址在 224.0.0.0 与 224.0.0.255(包括 224.0.0.0 和 224.0.0.255)范围之间的多播数据报,而不管其 TTL 值是多少。此地址范围是为使用路由协议以及其他低级拓扑搜索或维护协议(如网关搜索和组成员关系报告)而保留的。
即使主机拥有多个具有多播功能的接口,每个多播传输也是通过单个网络接口发送的。如果主机还用作多播路由器且 TTL 值大于 1,则多播可以转发到源接口之外的接口。可以使用套接字选项覆盖来自给定套接字的后续传输的缺省设置:
struct in_addr addr; setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF, &addr, sizeof(addr))
其中 addr 是所需传出接口的本地 IP 地址。通过指定地址 INADDR_ANY 恢复到缺省接口。使用 SIOCGIFCONF ioctl 获取接口的本地 IP 地址。要确定接口是否支持多播,请使用 SIOCGIFFLAGS ioctl 获取接口标志并测试是否设置了 IFF_MULTICAST 标志。此选项主要用于多播路由器以及其他专门针对 Internet 拓扑的系统服务。
如果将多播数据报发送到发送主机本身所属的组,则缺省情况下,本地传送的 IP 层将回送此数据报的副本。另一套接字选项可为发送主机提供针对是否回送后续数据报的显式控制:
u_char loop; setsockopt(sock, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop))
其中 loop 为 0 即为禁用回送,为 1 即为启用回送。此选项通过消除因接收应用程序自己的传输内容而产生的开销,可提高单台主机上只有一个实例的应用程序的性能。对于可以在一台主机上具有多个实例或者其发送主机不属于目标组的应用程序,不应使用此选项。
如果发送主机属于其他接口的目标组,则发送初始 TTL 值大于 1 的多播数据报可以传送到其他接口上的发送主机。回送控制选项不会影响此类传送。
主机必须成为一个或多个 IP 多播组的成员,才能接收 IP 多播数据报。进程可以使用以下套接字选项请求主机加入多播组:
struct ip_mreq mreq; setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq))
其中 mreq 为以下结构:
struct ip_mreq { struct in_addr imr_multiaddr; /* multicast group to join */ struct in_addr imr_interface; /* interface to join on */ }
每个成员关系都与单个接口关联。可以在多个接口上加入同一组。将 imr_interface 地址指定为 INADDR_ANY 以选择缺省的多播接口。还可以通过指定主机的本地地址之一来选择特定的具有多播功能的接口。
要删除成员关系,请使用:
struct ip_mreq mreq; setsockopt(sock, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq))
其中 mreq 包含用于添加成员关系的那些值。关闭套接字或中止保存套接字的进程将删除与此套接字关联的成员关系。可以有多个套接字请求成为特定组的成员,并且直到删除最后一个请求,主机才不再是此组的成员。
如果任一套接字请求成为数据报目标组的成员,则内核 IP 层将接受传入的多播包。给定套接字是否接收多播数据报取决于此套接字的关联目标端口和成员关系,或者取决于原始套接字的协议类型。要接收发送到特定端口的多播数据报,请将其绑定到本地端口,同时不指定本地地址,如使用 INADDR_ANY。
如果在 bind(3SOCKET) 之前存在以下内容,则可以将多个进程绑定到同一 SOCK_DGRAM UDP 端口:
int one = 1; setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one))
在这种情况下,每个目标为共享端口的传入多播或广播 UDP 数据报将传送到所有绑定到此端口的套接字。为了向后兼容,此传送不适用于传入的单播数据报。无论单播数据报的目标端口绑定有多少套接字,此类数据报永远都不会传送到多个套接字。 SOCK_RAW 套接字不要求 SO_REUSEADDR 选项共享单一 IP 协议类型。
可以在 <netinet/in.h> 中找到与多播相关的新套接字选项所需的定义。所有 IP 地址均以网络字节顺序传递。
要发送 IPv6 多播数据报,请在 ff00::0/8 范围中指定一个 IP 多播地址作为 sendto(3SOCKET) 调用的目标地址。
缺省情况下,IP 多播数据报的发送跃点限制为 1,此值可以阻止将数据报转发到单个子网之外。使用套接字选项 IPV6_MULTICAST_HOPS,可以将后续多播数据报的跃点限制设置为 0 到 255 之间的任何值。此功能用于控制多播的范围:
uint_l; setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &hops,sizeof(hops))
不能在任何子网中传输跃点限制为 0 的多播数据报,但是在以下情况下可以在本地范围内传送数据报:
发送主机属于目标组
启用了发送套接字上的多播回送
如果第一跃点子网连接到一个或多个多播路由器,则可以将跃点限制大于 1 的多播数据报传送到多个子网。与 IPv4 多播地址不同,IPv6 多播地址包含明确的范围信息,此信息在地址的第一部分进行编码。定义的范围如下,其中未指定 X:
节点-本地范围,限定在同一节点
链路-本地范围
站点-本地范围
组织-本地范围
全局范围
应用程序可独立于多播地址范围,使用不同的跃点限制值。例如,应用程序可以通过发送多播查询来对网络资源执行扩展环搜索,即第一个跃点限制值为 0,然后逐渐增大跃点限制值,直到收到回复为止。
即使主机拥有多个具有多播功能的接口,每个多播传输也是通过单个网络接口发送的。如果主机还用作多播路由器且跃点限制值大于 1,则多播可以转发到源接口之外的接口。可以使用套接字选项覆盖来自给定套接字的后续传输的缺省设置:
uint_t ifindex; ifindex = if_nametoindex ("hme3"); setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifindex, sizeof(ifindex))
其中,ifindex 是所需传出接口的接口索引。通过指定值 0 恢复到缺省接口。
如果将多播数据报发送到发送主机本身所属的组,则缺省情况下,本地传送的 IP 层将回送此数据报的副本。另一套接字选项可为发送主机提供针对是否回送后续数据报的显式控制:
uint_t loop; setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &loop, sizeof(loop))
其中,loop 为 0 即为禁用回送,为 1 即为启用回送。此选项通过消除因接收应用程序自己的传输内容而产生的开销,可提高单台主机上只有一个实例的应用程序(如路由器或邮件守护进程)的性能。对于可以在一台主机上具有多个实例的应用程序(如会议程序)或者其发送主机不属于目标组的应用程序(如时间查询程序),不应使用此选项。
如果发送主机属于其他接口的目标组,则发送初始跃点限制值大于 1 的多播数据报可以传送到其他接口上的发送主机。回送控制选项不会影响此类传送。
主机必须成为一个或多个 IP 多播组的成员,才能接收 IP 多播数据报。进程可以使用以下套接字选项请求主机加入多播组:
struct ipv6_mreq mreq; setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq))
其中 mreq 为以下结构:
struct ipv6_mreq { struct in6_addr ipv6mr_multiaddr; /* IPv6 multicast addr */ unsigned int ipv6mr_interface; /* interface index */ }
每个成员关系都与单个接口关联。可以在多个接口上加入同一组。将 ipv6_interface 指定为 0 以选择缺省的多播接口。为主机的其中一个接口指定接口索引以选择此具有多播功能的接口。
要离开组,请使用:
struct ipv6_mreq mreq; setsockopt(sock, IPPROTO_IPV6, IP_LEAVE_GROUP, &mreq, sizeof(mreq))
其中 mreq 包含用于添加成员关系的那些值。当关闭套接字或中止保存套接字的进程时,此套接字将删除关联的成员关系。可以有多个套接字请求成为特定组的成员。直到删除最后一个请求,主机才不再是此组的成员。
如果任一套接字已请求成为数据报目标组的成员,则内核 IP 层将接受传入的多播包。多播数据报是否传送到特定的套接字取决于与此套接字关联的目标端口和成员关系,或者取决于原始套接字的协议类型。要接收发送到特定端口的多播数据报,请将其绑定到本地端口,同时不指定本地地址,如使用 INADDR_ANY。
如果在 bind(3SOCKET) 之前存在以下内容,则可以将多个进程绑定到同一 SOCK_DGRAM UDP 端口:
int one = 1; setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one))
在这种情况下,所有绑定到此端口的套接字将接收每个目标为共享端口的传入多播 UDP 数据报。为了向后兼容,此传送不适用于传入的单播数据报。无论单播数据报的目标端口绑定有多少套接字,此类数据报永远都不会传送到多个套接字。 SOCK_RAW 套接字不要求 SO_REUSEADDR 选项共享单一 IP 协议类型。
可以在 <netinet/in.h> 中找到与多播相关的新套接字选项所需的定义。所有 IP 地址均以网络字节顺序传递。