如何解决检查`read`是否会返回EOF而不消耗任何数据
我有一个C程序,该程序通过(Linux)管道从另一个程序接收数据。如果要在写入任何数据之前关闭管道,我希望程序的行为有所不同。
执行此操作的自然方法是尝试从管道中读取并检查是否获得EOF
,但是如果有可用的话,它将消耗管道中的一些数据,并且(据我所知)没有办法将数据“返回”到管道中。
我要检查管道是否为空的程序部分与我处理数据的地方相距很远,因此我宁愿不必处理从第一次读取到此的数据保存。 / p>
有什么方法可以检查管道是否为空(read
将返回EOF
),而不是在不为空的情况下不消耗任何数据吗?
注意:如果管道尚未写入或关闭,我要做会阻塞。
解决方法
如果您使用Unix域流套接字而不是管道(这意味着将Call-Blocking
调用替换为socketpair(AF_UNIX,SOCK_STREAM,fds)
),则可以使用recv(fd,dummybuffer,1,MSG_PEEK)
来读取/接收一个字节的数据,而无需从接收缓冲区中删除它。
如果您不想阻塞,可以将pipe(fds)
与MSG_PEEK
结合使用;如果不想阻塞,则可以与MSG_DONTWAIT
结合使用,直到整个缓冲区都可以装满为止。
Unix域流套接字和管道之间的差异很小。流套接字是双向的,但是您可以使用shutdown(fd,SHUT_WR)
(或MSG_WAITALL
)关闭“写端”(分别是“读端”),这意味着另一端尝试从套接字读取,他们将立即获得流结束(SHUT_RD
,read()
等,返回0)。 (关闭“读取端”意味着当另一端尝试写入套接字时,它们将得到recv()
。)
现在,我什至无法想到为什么使用管道的程序不能与Unix域流套接字对一起使用的原因。
如果使用命名管道,则确实需要将EPIPE
和mkfifo()
更改为open()
,然后将socket(AF_UNIX,0)
更改为套接字地址。 bind()
,read()
,甚至更高级别的标准I / O设施在Unix域流套接字上也可以正常工作(使用write()
将套接字描述符转换为{{ 1}}句柄)。
如果您不能修改阅读器,则可以创建一个插入fdopen()
的最小动态库(这是当前C库在FILE
下使用的库),对除套接字路径,例如在环境变量中命名的套接字路径,而是创建一个套接字并绑定到该套接字路径。执行阅读器二进制文件时,只需将openat()
设置为指向此插入库。
换句话说,我确实相信从管道切换到Unix域流套接字没有真正的障碍。
您不能将fopen()
与管道一起使用,因为管道是在Linux中使用特殊文件系统而非套接字实现的。
不,您无法做您描述的事情。确定是否已到达管道等不可搜索文件末尾的方法是尝试从中读取文件。这不仅是自然的方法,而且是 the 方法。
,但是如果有的话,它将消耗管道中的一些数据 任何可用的
是的
(据我所知)没有办法放置数据 在管道中“返回”。
这取决于。如果您正在使用POSIX read()
阅读,则不会。如果将管端包装在FILE
中,并使用stdio函数读取它,那么将有ungetc()
。
尽管如此,
我要检查程序的一部分 管道为空,距离我处理数据的地方很远
似乎是一个设计问题。在实际获得获得数据或看到EOF之前,您不知道是否会获得数据。在对管道执行任何操作之前,管道写入端的进程可能会延迟任意时间,即使您提供了该进程,也无法完全控制其行为的这一方面。因此,从某种意义上说,在准备好使用数据之前尝试检查EOF并没有多大意义,因为您不能依靠没有阻塞就得到答案。
,所以我会 而不需要处理从我第一次读取到保存的数据 然后。
我想您必须要避免在没有数据要处理的情况下执行某种重量级的初始化。好的,但是我不知道有什么大不了的。您需要提供可以随时读取数据的存储空间。这样的事情怎么了:
void consume_pipe_data(int fd) {
char buffer[BUFFER_SIZE];
ssize_t count;
count = read(fd,buffer,BUFFER_SIZE);
if (count == 0) {
handle_no_data();
return;
} else if (count > 0) {
perform_expensive_initialization();
}
do {
if (count == -1) {
handle_error();
return;
}
consume_data(buffer);
count = read(fd,BUFFER_SIZE);
} while (count);
}
重点并不是要为您的程序提供适当的结构,而是可以对程序进行结构化,以便从初始读取中存储数据(如果有的话)非常干净自然。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。