c语言 - read() 在非阻塞套接字上"greedy"在 Linux 以外的平台上(OSX, FreeBSD)上?



考虑在非阻塞流模式套接字(SOCK_STREAM)上调用read():

ssize_t n = read(socket_fd, buffer, size);

假设远端对等端不会关闭连接,也不会关闭其写连接的一半(从本地的角度来看,是读连接的一半)。

在Linux上,在这种情况下,短读(n > 0 && n < size)意味着内核级读缓冲区已经耗尽,并且立即后续调用EAGAIN/EWOULDBLOCK通常会失败(除非在两次调用之间有新的数据到达,否则它会失败)。

换句话说,在Linux上,只要size足够大,read()的调用将总是消耗所有立即可用的资源。

同样,对于write(),在Linux上,短写总是意味着内核级缓冲区已被填满,并且对EAGAIN/EWOULDBLOCK的立即后续调用很可能失败。

问题1:这在macOS/OSX上也有保证吗?

问题2:这在FreeBSD上也是保证的吗?

问题3:这是POSIX要求/保证的吗?

我知道这在Linux上是正确的,因为epoll(第7节)的手册页中有以下注释:

对于面向流的文件(例如,管道,FIFO,流套接字),读/写I/O空间耗尽的情况也可以通过检查从目标文件描述符读取/写入的数据量来检测。例如,如果通过请求读取一定数量的数据来调用read(2),而read(2)返回的字节数较低,则可以确定已经耗尽了文件描述符的读I/O空间。使用write(2)写入时也是如此。(如果不能保证被监视的文件描述符总是指向面向流的文件,请避免使用后一种技术。)

编辑:作为这个问题的动机,考虑这样一种情况,您希望同时处理多个套接字上的输入,并且出于某种原因,您希望依次耗尽每个套接字的内核内缓冲区(即"深度优先"而不是"宽度优先")。显然,这可以通过在ready-ready套接字上重复读取直到EAGAIN/EWOULDBLOCK失败来实现,但是如果之前的读取很短,那么最后一次调用将是冗余的,并且我们知道短读取保证耗尽。

由Posix:

保证

数据一旦可用,应立即返回给用户。

…因此,在你提到的所有其他平台上也是如此,还有Windows、OS/2、NetWare……

最新更新