111-UDP 数据报被截断

1. 数据报被截断

有时候我们有这样的需求,在 udp 数据报传输的过程中,如果对方发过来的数据报很大,而我们的接收缓冲区不足以容纳这么大的数据报,怎么办?此时 udp 数据报就会被截断,有没有一种办法能判断数据报是否被截断呢?

先来看看 UDP 数据报被截断的行为,可能有下面三种:

  • 丢弃超出部分,并向上层返回 MSG_TRUNC 标志。需要使用 recvmsg 来接收这个标志。
  • 直接丢弃,不通知
  • 保留超出部分,并在下一次读取中返回

POSIX 采用第一种办法。早期的 SVR4 采用第三种办法。

2. 解决方案

  • 约定:如果接收的数据长度恰好等于缓冲区大小,就主观认为被截断,这种方法不精确,但是具有跨平台性
  • 使用 recvmsg,接收标志位

在后面的实验中,使用第二种方案。

3. 伪代码

完整代码托管在:http://git.oschina.net/ivan_allen/unp
本文程序路径:unp/program/advcudp/trunc

struct msghdr msg; // 填充 msg  recvmsg(sockfd, &msg, 0);  if (msg.msg_flags & MSG_TRUNC) {   // 信息被截断 }

4. 实验

  • 启动 udp 服务器
  • 启动 udp 客户端

由于接收方(服务器)缓冲区大小只有 20 字节,当收到的数据大小超过 20 字节时,数据报被截断,并返回 MSG_TRUNC 标志。


这里写图片描述
图1 数据报被截断

5. 总结

  • 掌握判断数据报被截断的方法

recvmsg 除了可以返回 MSG_TRUNC 标志位以外,还可以返回:

  • MSG_CTRUNC: 判断控制信息是否被截断
  • MSG_BCAST: 判断数据报是否是广播
  • MSG_MCAST: 判断数据报是否是多播

更多请参考 man 2 recvmsg