这是一个相当理论化的问题。如果套接字 I/O(read
或 write
)设置为 O_NONBLOCK
,但是此套接字在 fd_set
中设置为 select()
,其中 阻塞(等待文件描述符变为可读或可写的事件),那么该套接字无论如何阻塞(由于select()
)?
为什么我要将套接字设置为非阻塞,即使阻塞(默认)版本一旦变为可读(或可写)(感谢 select()
),也不会阻塞,因为 {{1 }} 表示它有数据要读取(或写入),因此套接字能够在不阻塞的情况下使用该数据执行其操作。那么为什么要在 select() 阻塞时设置套接字非阻塞呢?
具有 select()
套接字的示例,但是 与 阻塞 non-block
结合使用:
select()
答案 0 :(得分:2)
这是一个相当理论化的问题。如果套接字 I/O(读或写)设置为 O_NONBLOCK,但是此套接字在 fd_set 中设置为 select() 阻塞(等待文件描述符变为可读或可写的事件),则该套接字正在阻塞无论如何(由于 select())?
select
正在阻塞。套接字仍然是非阻塞的。
为什么我要将套接字设置为非阻塞,即使阻塞(默认)版本一旦变为可读(或可写)(感谢 select()),也不会阻塞,因为 select() 已经说过了有数据要读取(或写入),因此套接字能够在不阻塞的情况下使用该数据执行操作。
不,不,不!这不是一个安全的假设。不能保证后续的 read
或 write
不会阻塞。如果您需要将来保证以后的操作不会阻塞,则必须将套接字设置为非阻塞。
那么为什么在 select() 阻塞时还要设置套接字非阻塞呢?
因为您不希望套接字上的操作被阻塞。 select
函数不能保证未来的操作不会被阻塞,并且人们已经因为过去的假设而被烧毁。
例如,您在 UDP 套接字上执行 select
并表示接收不会阻塞。但是在您调用 recv
之前,管理员会启用之前禁用的 UDP 校验和。猜猜怎么着,如果唯一接收到的数据报上的校验和不正确,那么您的 recv
将被阻止。
除非您认为自己可以预见到类似事情可能发生的所有方式,并且您绝对不能,否则如果您不希望它阻塞,则必须将套接字设置为非阻塞。
答案 1 :(得分:2)
select
忽略文件描述符上的非阻塞标志,因为关注它没有任何意义。
select
正在(可能)同时检查多个文件描述符,它们可能具有不同的非阻塞标志。应该注意哪些?select
有自己的显式超时,用于确定调用是阻塞还是非阻塞,还是阻塞了有限的时间。可以说,在文件描述符上设置非阻塞“状态”标志是一个糟糕的设计——最好在每次调用时指定是阻塞还是非阻塞。如果您使用 recv
和 send
而不是 read
和 write
,您实际上可以做到这一点。所有在文件描述符上设置“非阻塞”的真正作用是它进行的调用不指定阻塞或非阻塞、非阻塞。