检查 `read` 是否会在不消耗任何数据的情况下返回 EOF

标签 c linux pipe posix

我有一个 C 程序,它通过(Linux)管道从另一个程序接收数据。如果在写入任何数据之前关闭管道,我希望程序的行为有所不同。
这样做的自然方法是尝试从管道中读取并检查我是否得到 EOF ,但是如果有可用的数据,这会消耗管道中的一些数据,并且(据我所知)没有办法将数据“放回”管道中。
我想检查管道是否为空的程序部分离我处理数据的地方很远,所以我宁愿不必处理保存我第一次读取的数据直到那时。
有没有办法检查管道是否为空( read 将返回 EOF )而不消耗任何数据以防它不为空?
注意:如果管道尚未写入或关闭,我确实希望它阻止。

最佳答案

如果您使用 Unix 域流套接字而不是管道 - 这意味着您替换了 pipe(fds) socketpair(AF_UNIX, SOCK_STREAM, 0, fds) 通话–,您可以使用 recv(fd, dummybuffer, 1, MSG_PEEK) 读取/接收一个字节的数据,而不将其从接收缓冲区中删除。
可以结合MSG_PEEKMSG_DONTWAIT如果您不想阻止,或使用 MSG_WAITALL如果要阻塞直到可以填充整个缓冲区。
Unix 域流套接字和管道之间的差异很小。流套接字是双向的,但您可以使用 shutdown(fd, SHUT_WR) (或 SHUT_RD )关闭“写端”(分别为“读端”),这意味着如果另一端尝试从套接字读取,他们将立即获得流结束( read()recv() 等返回 0)。 (关闭“读取端”意味着当另一端尝试写入套接字时,他们将得到 EPIPE 。)
现在,我什至想不出一个使用管道的程序不能使用 Unix 域流套接字对的原因。
如果您使用命名管道,您确实需要更改 mkfifo()open()socket(AF_UNIX, SOCK_STREAM, 0)后跟 bind()到套接字地址。 read() , write() ,甚至更高级别的标准 I/O 工具在 Unix 域流套接字之上也能正常工作(使用 fdopen() 将套接字描述符转换为 FILE 句柄)。
如果不能修改阅读器,可以创建一个最小的动态库,插入 openat() (这是当前 C 库在 fopen() 下使用的),调用原始 openat()对于除套接字路径之外的所有内容,例如在环境变量中命名,而是创建一个套接字并绑定(bind)到该套接字路径。执行阅读器二进制文件时,您只需设置 LD_PRELOAD指向这个插入库。
换句话说,我相信从管道切换到 Unix 域流套接字没有真正的障碍。
您不能使用 recv()使用管道,因为在 Linux 中管道是使用特殊文件系统实现的,而不是套接字。

关于检查 `read` 是否会在不消耗任何数据的情况下返回 EOF,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63403148/

相关文章:

plot - 如何从 stdin 读取数据到 gnuplot 并绘制相同的数据两次

c - 从标准输入 C 读取所有数据

c - 错误 : expected expression before "{"

c - 如何在给定边长的情况下找到斜角四面体的面的角度

linux - 在lampp stack ubuntu上运行github克隆项目时出现服务器500错误

Python Popen 挂起与 psexec - 不希望的结果

c - 用 C 读取文本文件,将行分成多个变量

python - 如何在十六进制Linux终端中发送参数

Linux 证书生成

c - 在 c 中使用 Pipe() 卡在 read() 上的程序