59-UDP 数据报丢失

1. 程序路径

代码托管在 gitos 上,请使用下面的命令获取:

git clone https://git.oschina.net/ivan_allen/unp.git

如果你已经 clone 过这个代码了,请使用 git pull 更新一下。本节程序所使用的程序路径是 unp/program/echo_udp/basic

2. UDP 数据报丢失

UDP 是不可靠的,它不像 TCP 能够保证数据一定到达对端接收缓冲区。上一节我们写的 basic/echo 程序就会遇到这样的问题:客户端无法确认发送的数据是否到达对端接收缓冲区。

实际上,每个 UDP 套接字都有一个接收缓冲区,所有到达该套接字的数据报按顺序进入缓冲区。当进程调用 recvfrom 时,缓冲区中的下一个数据报以 FIFO(先进先出)顺序返回给进程。

回到我们的 basic/echo 客户端,它的伪代码像下面这样:

while(1) {   gets(buf);// 从标准输入读入数据   sendto(sockfd, buf, servaddr); // 发送给服务器   recvfrom(sockfd, buf, NULL); // 接收数据   puts(buf); }

如果客户端在 sendto 的时候,udp 报文没有顺利到达对方,那么客户端将永远阻塞在 recvfrom 上。

3. 实验

在 sun 主机上启动客户端,给一个 ip 地址不存在或者端口不存在的服务器发信息。

  • 主机存在,服务器未启动(端口不存在)
$ ./echo -h mars


这里写图片描述
图1 主机存在,服务器未启动

可以看到,tcpdump 产生了一个 ICMP 报文:udp 端口不可达的信息。可惜的是,此错误并没有报告给应用程序。sendto 的返回值根本检测不到这种情况。

  • 主机不存在(flower 还没有开机)
$ ./echo -h flower


这里写图片描述
图2 flower 还没开机

服务器不存在,tcpdump 发送 ARP 请求报文,此错误也不会报告给应用进程~

上面两种情况,导致客户端阻塞在了 recvfrom 上,永远没有继续执行的机会。

当然,这个实验并没有真正的模拟数据报丢失的情况,要想在服务器启动的情况下模拟数据报丢失是很难的,我们不妨假设服务器启动了,但是到服务器的某个中间路由器正好宕机了,那么这种情况就非常像前面的两个实验了。

4. 如何解决问题?

有一些可用的解决方案,比如给 recvfrom 设置超时。如果超过一定的时间,recvfrom 还没有返回,基本上就可以认为数据报丢失,重新回到 sendto 继续执行。

还有一种方案是使用多线程,我们将发送和接收放到两个不同的线程中去执行。

还有其它更多的方案,比如给 udp 增加可靠性,模拟 tcp 协议,给 udp 程序添加两个特性:超时和和重传、序列号。

这些话题我们现在保留,以后继续讨论。

5. 总结

  • UDP 数据报会丢失
  • UDP 是不可靠的

说明:本文转自blog.csdn.net,用于学习交流分享,仅代表原文作者观点。如有疑问,请联系我们删除~