【发布时间】:2014-07-25 13:47:50
【问题描述】:
在处理 UDP 套接字时,什么会导致 sendto() 发送的字节数少于请求的字节数?
提出这个问题的动机是找出我需要采取的预防措施,以确保我总是在一次调用 sendto() 时收到完整的消息,并了解我需要采取哪些进一步的步骤需要采取将一条消息转换成单个 IP 数据包。我是否只需要确保我的消息小于某个大小,如果是,该大小有多大?除了特定于操作系统的 UDP 数据报大小限制和 MTU,还有其他因素在起作用(例如 i/o 缓冲区容量、反复无常的操作系统)?
问完上面的主要问题,在这篇文章的标题中,我会继续一些相关的后续问题,然后在最后把事情放在上下文中。
其他问题
更详细地说,再次假设我们正在对 UDP 套接字进行操作:
-
每次对
sendto()的成功调用是否会准确发送1 个UDP 数据报? (我很欣赏这可能会分成多个 IP 数据包) -
每次对
recvfrom()的成功调用会准确检索1 UDP 数据报吗? -
如果一条消息需要 N 次调用
sendto()来发送,那么即使接收机器是不同的平台? (我很欣赏数据报的顺序是不可预测的) -
假设我尝试发送一条消息,其大小等于或小于本地和远程系统支持的最大 UDP 数据报大小中的较小者,(并且出现一些错误,导致返回值 -1)
sendto()保证一次性发送我的全部信息吗?或者它可能会报告它发送的字节数少于我要求它发送的字节数?如果是这样,为什么?回到问题 1。 -
除了问题 4 中的假设,假设我的消息不大于 (MTU - UDP header - IP header) 大小,那么保证结果的 UDP 数据报适合 1 IP 数据包(至少在我的本地网络上)?
上下文
我刚刚开始编写我的第一个基于 UDP 的通信协议(跨平台:例如 linux、mac、windows、ios、android 等)。我是一个套接字新手,但我知道使用像 UDP 这样简单的协议所带来的“成本”,并研究了以下算法/策略:
- Reliability and flow control
- 将大消息拆分为多个小消息
- Fountain codes 帮助补偿一些数据包丢失(通过减少重新发送请求)。
- 加密(参见 http://srp.stanford.edu/)
我正在尝试将我的所有通信分解为原子消息(即单个、自包含的 UDP 数据报),这些消息可能(但不一定)需要装入单个 IP 数据包(例如 1500 字节)。吞吐量和数据包丢失的实时评估将确定我是否必须缩小数据报以适应单个 IP 数据包(这会导致额外标头的大小损失)。其中一些将通过 wifi/无线电链接,所以我希望自适应地确定“最佳”数据报大小。我知道我所有接口的 MTU,并且理解在我的本地网络之外,数据包可能会被进一步拆分,但这不在我的控制范围内,所以我可以忍受它。
但一切都取决于能够构造一个原子消息,并且有 100% 的信心我可以通过一次调用 sendto() 成功发送它,并通过一次调用 recvfrom() 接收它。我所有的应用程序级可靠性、拆分、编码和加密信息都存在于我自己的协议标头中,并且在调用 sendto() 后我无法重新拆分消息。例如。考虑一个消息校验和:如果整个消息没有一次性通过,则标头中的校验和对于已发送的消息部分不再有效。
【问题讨论】: