10

我在理解 recv()/recvfrom() 从非阻塞 UDP 套接字返回什么时遇到了问题。

更具体一点,与 TCP 相比(如果我错了,请纠正我):

  • 在缓冲区中有一些数据之前,阻塞套接字(TCP 或 UDP)不会从 recv() 返回。这可能是一些字节数 (TCP) 或完整的数据报 (UDP)。

  • 非阻塞 TCP 套接字返回 EWOULDBLOCK (linux) / WSAEWOULDBLOCK (windows) 或当前在缓冲区中的字节。由于 TCP 数据是一个流,因此返回多少字节并不重要。

现在的问题:

  • 如果没有可用数据,非阻塞 UDP 套接字也会返回 WOULDBLOCK (linux) / WSAEWOULDBLOCK (windows)。但是,如果有数据可用,非阻塞 UDP 套接字是否只返回一些字节,这可能意味着您只能获得一半的数据报,或者 UDP 套接字是否总是返回完整的数据报?

编辑:

我所说的“一半数据报”的意思是:如果我在套接字当前正在接收数据报的那一刻调用 recv() 会发生什么。在那一刻,缓冲区中有一些字节,但数据报还没有完成。

感谢您的解释和评论。谢谢!

4

3 回答 3

10

最后,找个借口从旧办公室的箱子里翻出我的史蒂文斯书。

如果缓冲区足够大,标准的 Berkeley 套接字recv()recvfrom()函数将永远不会返回部分数据报。在内核完全接收并重新组装数据报之前,该数据报对应用程序不可用。

有趣的是,今天这不是什么(任何?)问题,当提供的缓冲区太小时,其他网络编程接口不同意行为:

传统的 Berkeley 版本的套接字 API 会截断数据报,丢弃任何多余的数据。是否通知应用程序取决于版本。(4.3BSD Reno 及更高版本可以通知应用程序数据报被截断。)

SVR4(包括 Solaris 2.x)下的套接字 API 不会截断数据报。任何多余的数据都会在后续读取中返回。应用程序不会收到从单个 UDP 数据报完成多个读取的通知。

TLI API 不会丢弃数据。而是返回一个标志,指示更多数据可用,并且应用程序的后续读取返回数据报的其余部分。

(Stevens,TCP/IP 图解,第 1 卷,第 160 页)

于 2010-02-10T22:16:39.557 回答
2

是的,UDP 只返回该数据报中传输的数据。UDP 不像 TCP 那样面向流。数据报是离散的传输,并没有以任何方式真正与其他数据报相关联。这就是 TCP 的套接字选项是 SOCK_STREAM 的原因。

这样做的好处是您可以感觉到单独的传输,这对于 TCP 来说并不容易做到。

于 2010-02-10T20:23:30.177 回答
0

我相信你会得到一个或零个数据报。但我现在无法支持这一点。也许其他人可以提供一个很好的参考?

编辑:我很确定你不能收到半个数据报。数据报要么已经到达缓冲区,要么没有。

于 2010-02-10T20:22:20.697 回答