Linux read()是否会在select()之后阻塞?

Linux read()是否会在select()之后阻塞?,linux,sockets,Linux,Sockets,我正在通过TCP/IP套接字读取数据流。水流负载非常不均匀。有时每秒都会有大量数据到达,有时一小时内都没有数据。在长时间不活动的情况下(远程服务器没有数据,但连接仍然在线),我的程序应该采取一些措施 我正在使用select()实现超时。它告诉我是否有数据准备就绪,但我不知道在不导致read()阻塞的情况下可以读取多少数据。阻塞是不可接受的,因为它可能持续的时间远远超过我需要的超时时间 为了提高效率,流被读入大的缓冲区中,并使用该缓冲区大小提供read()调用 如果要填充的缓冲区大于套接字中当前可

我正在通过TCP/IP套接字读取数据流。水流负载非常不均匀。有时每秒都会有大量数据到达,有时一小时内都没有数据。在长时间不活动的情况下(远程服务器没有数据,但连接仍然在线),我的程序应该采取一些措施

我正在使用select()实现超时。它告诉我是否有数据准备就绪,但我不知道在不导致read()阻塞的情况下可以读取多少数据。阻塞是不可接受的,因为它可能持续的时间远远超过我需要的超时时间

为了提高效率,流被读入大的缓冲区中,并使用该缓冲区大小提供read()调用


如果要填充的缓冲区大于套接字中当前可用的数据量,read()会在select()之后阻塞吗

否,
read()
将读取到指定的大小,并返回实际读取的字节数,可以更小。

O\u NONBLOCK
,可由
fcntl
/
F\u SETFL
设置,并应导致非阻塞
read

您可以使用默认情况下不阻塞的recv()(如果未指定标志MSG_WAITALL)

实际上它不应该阻塞(这就是select()的作用!),但事实上,它可能会异常地阻塞。通常,read()应该返回到您指定的最大字节数,其中可能包括零字节(这实际上是一种有效的情况!),但在之前报告准备就绪后,它不应阻塞

不过,请参见Linux手册页:

在Linux下,select()可能会报告 套接字文件描述符为“准备就绪” “阅读”,尽管如此 后续读取块。这可能会导致 例如,当数据被删除时会发生这种情况 已到,但经检查有误 校验和被丢弃。可能存在 是指在其他情况下 描述符被错误地报告为 准备好了。这样使用起来可能更安全 O_非阻塞不应 街区


阻塞的文件描述符将在读取时阻塞(),直到有内容可读取为止-可能是一个字节或整个请求。如果没有内容可读取,则非阻塞描述符不会在读取时阻塞。Select()不是读取()。它基本上会使进程进入睡眠状态并监视文件描述符,包括非阻塞描述符。当其中一个描述符上存在活动(或超时期限到期)时,选择returns,您可以读取数据,或者在超时的情况下执行其他操作


因此,您有两个不同的问题。(1)您想在没有数据时“采取一些措施”。这是选择超时。(2)一旦您有数据(由选择通知),您就不想在读取时阻塞。这是非阻塞模式。当您在非阻塞读取上获得EAGAIN时,您将返回到选择和/或“采取一些措施”然后循环返回选择。

如何使用此选项实现有效超时?循环不是选项。睡眠循环对其响应时间有害。哦,我明白了。你的意思是选择和非阻塞读取的组合。不太方便,但如果没有更好的选项,就可以了。将在非阻塞描述符上选择阻塞吗?手册说它将l如果下一次读取调用不阻塞,则返回。非阻塞描述符不会阻塞。@Basilevs:我很确定
select()
将等待非阻塞描述符上有数据(或文件结尾)。@Basilevs,我的手册说,“将监视
readfds
中列出的那些描述符,以查看字符是否可用于读取(更准确地说,查看读取是否不会阻塞;特别是,文件描述符也在文件末尾准备就绪)。我想这是修复原始句子的方法,当
read
即使没有可用字符也会立即返回。顺便说一句,不要忘了
select
可能会被信号中断,比描述符上的任何事件或超时都要早。我希望代码与未命名管道尽可能兼容,就像pos一样sible,我不确定recv是否会与它们一起工作。-1手册说:如果套接字上没有可用的消息,则接收呼叫将等待消息到达,除非套接字是非阻塞的(参见fcntl(2))在这种情况下,返回值-1,外部变量errno设置为EAGAIN。@Basilevs:MKo肯定意味着MSG_DONTWAIT
read
将在完全没有可用字节的情况下被阻塞,而且我记得,如果描述符处于阻塞模式,它还不是文件的结尾。完全正确。继续使用
select()
,但将套接字设置为非阻塞状态,当
select()
显示其可读性时,调用
read()
,直到它返回
EAGAIN
。不,零字节不是有效的事情(EOF除外);请参阅下的POSIX规范recv()。Linux select()记录的行为手册页也是一种违反。至少从1985年起,每个Unix都是这样工作的;如果你的Unix没有,那么你的Unix就坏了。@Nemo:你想说什么?(1)有人可能会认为EOF和有序关机是可能发生的事情,也是程序应该预料并准备处理的一种情况。(2)这个问题是针对Linux的,只要回答指出Linux的特殊行为就足够了。(3)尽管与此无关,但这种行为并不是严格违反POSIX,因为POSIX允许条件(OOB数据的到达就是一个例子)即使后续的
recv
会阻塞,也会将套接字标记为就绪。这是一个罕见的事件,但可能也是合法的。我是说
recv()
返回零意味着有序关机(或EOF)而不是任何其他事情。是的,此选择()行为违反了POSIX;非内联OOB数据没有将套接字标记为select()可以读取。(在中搜索“OOB”)。POSIX根本不允许您提到的任何一项,句号。Linux违反