103-使用广播的 UDP 回射客户端

讲了好几篇有关广播的理论,是时候实践一下了。这一次,需要将之前写的 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 套接字选项才能广播