在Linux(OSX,FreeBSD)以外的平台上,非阻塞套接字上的read()是“贪婪的”吗?

时间:2016-10-19 03:51:28

标签: c macos sockets freebsd nonblocking

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

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

假设远程对等体不会关闭连接,并且不会关闭其写入的一半连接(从本地角度来看,读取一半)。

在Linux上,在这些情况下进行简短读取(n > 0 && n < size)意味着内核级读取缓冲区已用尽,并且立即后续调用通常会因EAGAIN / {{而失败1}}(除非新数据设法在两次调用之间到达,否则它将失败)。

换句话说,在Linux上,如果EWOULDBLOCK足够大,read()的调用将始终消耗所有可立即使用的内容。

同样对于size,在Linux上,短写总是意味着内核级缓冲区被填充,并且立即后续调用可能会因write() / EAGAIN而失败

问题1:macOS / OSX上是否也保证了这一点?

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

问题3:这是否需要/由POSIX保证?

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

  

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

编辑:作为问题的动机,考虑一种情况,你想同时处理多个套接字上的输入,无论出于何种原因,你想通过依次完全耗尽每个套接字的内核缓冲区来做到这一点(即“深度优先”而不是“广度优先”)。显然可以通过在就绪就绪套接字上重复读取直到它以epoll / EAGAIN失败来完成,但如果前一次读取很短,则最后一次调用将是多余的,并且我们知道简短的阅读是对疲惫的保证。

1 个答案:

答案 0 :(得分:1)

Posix保证:

  

数据一旦可用就会返回给用户。

...因此,您提到的所有其他平台,以及Windows,OS / 2,NetWare,......

任何其他实施都没有意义。