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),前提是此接口支持广播或点对点寻址。