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