IPv6 不支持广播,仅 IPv4 支持广播。
数据报套接字发送的消息可以广播到已连接网络中的所有主机。此网络必须支持广播,因为系统不在软件中提供任何广播模拟。广播消息会给网络带来很高的负载,因为广播消息会强制网络中的每台主机都为其服务。通常出于以下两个原因之一使用广播:
在未提供资源地址的情况下在本地网络中查找资源
某些功能要求将信息发送到所有可访问的相邻主机
要发送广播消息,请创建一个 Internet 数据报套接字:
s = socket(AF_INET, SOCK_DGRAM, 0);
将一个端口号绑定到此套接字:
sin.sin_family = AF_INET; sin.sin_addr.s_addr = htonl(INADDR_ANY); sin.sin_port = htons(MYPORT); bind(s, (struct sockaddr *) &sin, sizeof sin);
通过将数据报发送到网络的广播地址可以仅在此网络中进行广播。 通过将数据报发送到 netinet/in.h 中定义的特殊地址 INADDR_BROADCAST 可以在所有已连接的网络中进行广播。
系统会提供一种机制来确定多条有关系统上网络接口的信息。这些信息包括 IP 地址和广播地址。SIOCGIFCONF ioctl(2) 调用会以单一的 ifconf 结构返回主机的接口配置。此结构包含一个 ifreq 结构数组。主机连接的每个网络接口所支持的所有地址族都具有自己的 ifreq 结构。
以下示例给出了 net/if.h 中定义的 ifreq 结构。
struct ifreq { #define IFNAMSIZ 16 char ifr_name[IFNAMSIZ]; /* if name, e.g., "en0" */ union { struct sockaddr ifru_addr; struct sockaddr ifru_dstaddr; char ifru_oname[IFNAMSIZ]; /* other if name */ struct sockaddr ifru_broadaddr; short ifru_flags; int ifru_metric; char ifru_data[1]; /* interface dependent data */ char ifru_enaddr[6]; } ifr_ifru; #define ifr_addr ifr_ifru.ifru_addr #define ifr_dstaddr ifr_ifru.ifru_dstaddr #define ifr_oname ifr_ifru.ifru_oname #define ifr_broadaddr ifr_ifru.ifru_broadaddr #define ifr_flags ifr_ifru.ifru_flags #define ifr_metric ifr_ifru.ifru_metric #define ifr_data ifr_ifru.ifru_data #define ifr_enaddr ifr_ifru.ifru_enaddr };
可以获取接口配置的调用为:
/* * Do SIOCGIFNUM ioctl to find the number of interfaces * * Allocate space for number of interfaces found * * Do SIOCGIFCONF with allocated buffer * */ if (ioctl(s, SIOCGIFNUM, (char *)&numifs) == -1) { numifs = MAXIFS; } bufsize = numifs * sizeof(struct ifreq); reqbuf = (struct ifreq *)malloc(bufsize); if (reqbuf == NULL) { fprintf(stderr, "out of memory\n"); exit(1); } ifc.ifc_buf = (caddr_t)&reqbuf[0]; ifc.ifc_len = bufsize; if (ioctl(s, SIOCGIFCONF, (char *)&ifc) == -1) { perror("ioctl(SIOCGIFCONF)"); exit(1); } ... }
使用此调用之后,buf 将包含一个 ifreq 结构数组。主机所连接的每个网络都具有一个关联的 ifreq 结构。这些结构的排序顺序有两种:
按接口名称的字母顺序
按支持的地址族的数值顺序
ifc.ifc_len 的值设置为 ifreq 结构所使用的字节数。
每个结构都有一组指示相应网络为运行或关闭、点对点或广播等等的接口标志。以下示例说明了 ioctl(2) 针对 ifreq 结构所指定的接口返回 SIOCGIFFLAGS 标志。
struct ifreq *ifr; ifr = ifc.ifc_req; for (n = ifc.ifc_len/sizeof (struct ifreq); --n >= 0; ifr++) { /* * Be careful not to use an interface devoted to an address * family other than those intended. */ if (ifr->ifr_addr.sa_family != AF_INET) continue; if (ioctl(s, SIOCGIFFLAGS, (char *) ifr) < 0) { ... } /* Skip boring cases */ if ((ifr->ifr_flags & IFF_UP) == 0 || (ifr->ifr_flags & IFF_LOOPBACK) || (ifr->ifr_flags & (IFF_BROADCAST | IFF_POINTOPOINT)) == 0) continue; }
以下示例使用 SIOGGIFBRDADDR ioctl(2) 命令来获取接口的广播地址。
if (ioctl(s, SIOCGIFBRDADDR, (char *) ifr) < 0) { ... } memcpy((char *) &dst, (char *) &ifr->ifr_broadaddr, sizeof ifr->ifr_broadaddr);
还可以使用 SIOGGIFBRDADDR ioctl(2) 来获取点对点接口的目标地址。
获取接口广播地址之后,使用 sendto(3SOCKET) 传输广播数据报:
sendto(s, buf, buflen, 0, (struct sockaddr *)&dst, sizeof dst);
针对主机所连接的每个接口使用 sendto(3SOCKET),前提是此接口支持广播或点对点寻址。