有很多 fd 无法读取(例如,侦听套接字)。如何测试read
fd 上的 (2) 是否会返回EINVAL
,而不会冒险取出数据?
不起作用的事情:
我们可以
read()
使用传递的零字节缓冲区来做 a。但这被排除在外:read()
允许但不要求实现对零字节请求执行错误检查。[从 POSIX 1003.1-2008]我们可能很想调用
select()
描述符。不幸的是,select()
可读集的语义非常重载,因此会告诉 fd 是“可读的”,而实际上调用它是错误的read()
(例如,侦听套接字将被标记为“可读”但需要accept()
,不read()
,和还有其他不可移植的示例,例如 event 或 kqueue fds)。(某种工作)阅读您编译的每个平台的手册页,使用特定的系统调用测试 fd,以生成大致如下所示的函数:
int isReadable(int fd) { return isActiveSocket(fd) || isFifo(fd) || isRegFile(fd) || isEventFd(fd) || ... /* more pain */ }
(某种作品)请注意,
read()
对于 fd 是否是系统调用的正确类型,它本身并不一定会给您一个很好的答案!令人惊讶的是,EINVAL
在 POSIX 中未指定read()
(STREAMS 除外),但在 linux 上提供给您(“EINVAL:fd 附加到一个不适合读取的对象”)并且在 BSD 上相当神秘(“EINVAL:与[fd] 是否定的。”)。
场景
有人启动了您的应用程序,您想知道值为 0 的 fd 是否是伪造的(例如侦听套接字),或者是否有可能从中读取。你不想尝试实际read()
的 a) 因为那会阻塞,b) 因为在取出数据后你不能把它塞回去。