UDP 提供什么保证?
What guarantees does UDP give?
UDP数据包明明可以多次到达,根本不会,乱序。
但是,如果数据包到达,是否可以保证对 recvfrom
和类似函数的任何调用都会 return 发件人通过 sendto
(或类似)发送的一个完整数据包?换句话说,是否有可能一次收到不完整的数据包或多个数据包?它取决于 OS,还是标准强制执行某种行为?
recv 系列系统调用的行为并非如此。它们不 return 帧 或 数据包 ,它们将存储在处理器内部接收缓冲区中的第 3 层有效载荷字节传输到 用户应用程序缓冲区。也就是说,最终决定向上传递多少字节的是用户缓冲区的大小。行为是尝试填充此缓冲区,如果不可能发送已到达的数据,如果不可能则阻止或 return 没有数据,具体取决于 recv 的配置方式。
来自the recv man page(我强调)
If a message is too long to fit in the supplied buffer,
excess bytes may be discarded depending on the type of socket the
message is received from.
If no messages are available at the socket, the receive calls wait
for a message to arrive, unless the socket is nonblocking (see
fcntl(2)), in which case the value -1 is returned and the external
variable errno is set to EAGAIN or EWOULDBLOCK. The receive calls
normally return any data available, up to the requested amount,
rather than waiting for receipt of the full amount requested.
另一个需要考虑的因素是内部接收缓冲区大小。这是一个固定大小,尝试向已经满的缓冲区添加更多数据可能会导致数据丢失。该值可以使用 SO_RCVBUF 标志设置 - 来自 socket man page:
SO_RCVBUF Sets or gets the maximum socket receive buffer in bytes. The
kernel doubles this value (to allow space for bookkeeping
overhead) when it is set using setsockopt(2), and this doubled
value is returned by getsockopt(2). The default value is set
by the /proc/sys/net/core/rmem_default file, and the maximum
allowed value is set by the /proc/sys/net/core/rmem_max file.
The minimum (doubled) value for this option is 256.
正如我在评论中提到的,UDP 规范 (RFC 768) 没有指定应用程序与处理 UDP 消息的 OS 基础设施之间“接口”的行为。
但是,POSIX specification确实解决了这个问题。 recvfrom
规范的关键部分是这样说的:
The recvfrom()
function shall return the length of the message written to the buffer pointed to by the buffer argument. For message-based sockets, such as SOCK_RAW
, SOCK_DGRAM
, and SOCK_SEQPACKET
, the entire message shall be read in a single operation. If a message is too long to fit in the supplied buffer, and MSG_PEEK is not set in the flags argument, the excess bytes shall be discarded.
注意“应”一词的使用。任何声称符合 POSIX 规范的 OS <-> 应用程序 API 都将受该语言的约束。
简单来说,只要提供的缓冲区space足够大,任何符合POSIX 的recvfrom
都会return 缓冲区中有一个完整的UDP 消息。如果它不够大,“多余”的字节将被丢弃。
(一些 recvfrom
实现支持 non-standard MSG_TRUNC
标志,允许应用程序找出实际消息长度。查看 OS-specific 手册页了解详细信息。 )
UDP数据包明明可以多次到达,根本不会,乱序。
但是,如果数据包到达,是否可以保证对 recvfrom
和类似函数的任何调用都会 return 发件人通过 sendto
(或类似)发送的一个完整数据包?换句话说,是否有可能一次收到不完整的数据包或多个数据包?它取决于 OS,还是标准强制执行某种行为?
recv 系列系统调用的行为并非如此。它们不 return 帧 或 数据包 ,它们将存储在处理器内部接收缓冲区中的第 3 层有效载荷字节传输到 用户应用程序缓冲区。也就是说,最终决定向上传递多少字节的是用户缓冲区的大小。行为是尝试填充此缓冲区,如果不可能发送已到达的数据,如果不可能则阻止或 return 没有数据,具体取决于 recv 的配置方式。
来自the recv man page(我强调)
If a message is too long to fit in the supplied buffer, excess bytes may be discarded depending on the type of socket the message is received from.
If no messages are available at the socket, the receive calls wait for a message to arrive, unless the socket is nonblocking (see fcntl(2)), in which case the value -1 is returned and the external variable errno is set to EAGAIN or EWOULDBLOCK. The receive calls normally return any data available, up to the requested amount, rather than waiting for receipt of the full amount requested.
另一个需要考虑的因素是内部接收缓冲区大小。这是一个固定大小,尝试向已经满的缓冲区添加更多数据可能会导致数据丢失。该值可以使用 SO_RCVBUF 标志设置 - 来自 socket man page:
SO_RCVBUF Sets or gets the maximum socket receive buffer in bytes. The kernel doubles this value (to allow space for bookkeeping overhead) when it is set using setsockopt(2), and this doubled value is returned by getsockopt(2). The default value is set by the /proc/sys/net/core/rmem_default file, and the maximum allowed value is set by the /proc/sys/net/core/rmem_max file. The minimum (doubled) value for this option is 256.
正如我在评论中提到的,UDP 规范 (RFC 768) 没有指定应用程序与处理 UDP 消息的 OS 基础设施之间“接口”的行为。
但是,POSIX specification确实解决了这个问题。 recvfrom
规范的关键部分是这样说的:
The
recvfrom()
function shall return the length of the message written to the buffer pointed to by the buffer argument. For message-based sockets, such asSOCK_RAW
,SOCK_DGRAM
, andSOCK_SEQPACKET
, the entire message shall be read in a single operation. If a message is too long to fit in the supplied buffer, and MSG_PEEK is not set in the flags argument, the excess bytes shall be discarded.
注意“应”一词的使用。任何声称符合 POSIX 规范的 OS <-> 应用程序 API 都将受该语言的约束。
简单来说,只要提供的缓冲区space足够大,任何符合POSIX 的recvfrom
都会return 缓冲区中有一个完整的UDP 消息。如果它不够大,“多余”的字节将被丢弃。
(一些 recvfrom
实现支持 non-standard MSG_TRUNC
标志,允许应用程序找出实际消息长度。查看 OS-specific 手册页了解详细信息。 )