讲了好几篇有关广播的理论,是时候实践一下了。这一次,需要将之前写的 udp 回射服务器和客户端拿过来,稍作修改。你可以直接去 unp/program/template
这个模板文件夹下面把 udp 的代码拿过来改。
本文使用的程序工具托管在 gitos 上:http://git.oschina.net/ivan_allen/unp
- 模板路径:
unp/program/template
- 本文程序路径:
unp/program/broadcast/basic
再讨论一点:使用 UDP 而不使用 TCP,是因为 TCP 不支持广播!
1. 程序设计
这个程序非常简单,只要在客户端中修改两处:
- 因为客户端可以发送广播,则应该循环 recvfrom
- Linux 是默认情况下禁止发送广播的,要想发送广播,需要指定套接字选项 SO_BROADCAST.
1.1 循环 recvfrom
// sendto ... alarm(2); for(;;) { addrlen = sizeof(cliaddr); nr = recvfrom(sockfd, buf, 4096, 0, (struct sockaddr*)&cliaddr, &addrlen); // 引自有竞争漏洞 if (nr < 0) { if (errno == EINTR) break; ERR_EXIT("recvfrom"); } LOG("from %s:%d ", inet_ntoa(cliaddr.sin_addr), ntohs(cliaddr.sin_port)); nw = iwrite(STDOUT_FILENO, buf, nr); if (nr < 0) { ERR_EXIT("iwrite"); } }
注意到上面的注释部分,标记有漏洞。如果 ALARM 信号在此处产生,则程序会永久阻塞在 recvfrom 上。这样写代码的方式在前面已经遇见很多次了,但是一直没有提,后面我们必须得解决它!
1.2 开启套接字选项 SO_BROADCAST
如果你不开启此选项,直接发广播,程序会报权限错误(root 身份也不行!)
int onoff = 1; setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &onoff, sizeof(onoff));
在创建客户端的套接字后,执行上面两行即可。
2. 运行结果
这里需要多开几台虚拟机,我这里用了三台,分别是是 sun(192.168.166.188),moon(192.168.166.242),flower(192.168.166.47)。然后在这三台主机上启动 udp 服务器:
$ ./udp -s
接下来,在 sun 主机上启动客户端(sun 主机既启动服务器,又运行客户端)。
图1 本地子网定向广播
图2 受限广播
3. 总结
- 掌握使用 UDP 进行广播的方法
- 需要开启 SO_BROADCAST 套接字选项才能广播