如何向文件描述符发出 EOF(同时保持打开状态)?

如何向文件描述符发出 EOF(同时保持打开状态)?

我的程序可以调用哪些代码来实现与在终端中按Ctrl+类似的行为?D也就是说,要使read在 STDIN 上调用的函数在子进程中返回0,但不会在父进程中关闭此“STDIN”文件描述符?

我试图了解 EOF 条件如何传达给 Linux 中的进程。

看来read返回0只是建议性的,遇到这样的EOF情况后实际上可以继续阅读。考虑以下程序:

#include <unistd.h>
#include <stdio.h>

void terminate_buf(char *buf, ssize_t len)
{
    if(len > 0) {
        buf[len-1] = '\0';
    } else {
        buf[0] = '\0';
    }
}

int main()
{
    int r;
    char buf[1024];

    while(1) {
        r = read(0, buf, 1024);
        terminate_buf(buf, r);
        printf("read %d bytes: %s\n", r, buf);
    }

    return 0;
}

如果您编译(gcc -o reader reader.c假设您将其命名为 reader.c)并在终端中运行该程序,然后按Ctrl+ D,然后输入foobarEnter,您将看到以下内容:

$ ./reader 
read 0 bytes: 
foobar
read 7 bytes: foobar


表明在 EOF 事件发生后完全有可能读取有意义的数据。您可以在一行上多次按Ctrl+ ,然后按一些文本,然后继续读取数据,就好像什么也没发生一样(在每次按+打印“read 0 bytes: ”之后)。文件描述符保持打开状态。DreaderCtrlD

那么这里发生了什么以及我如何复制这种行为?如何使子进程在看到 EOF 后看到一些数据?有没有办法只使用常规文件 I/O(也许还有ioctls)来做到这一点,或者我需要打开一个 pty?计数为 0 的调用write似乎不起作用,read甚至在另一端也没有返回。什么EOF,真的吗?

答案1

Ctrl-D (0x04) 由终端设备映射到 EOF。如果您从管道或文件中读取数据,则不会发生这种情况。

echo -e "a\x04b" | cat

或者

echo -e "a\x04b" | hd

例如,如果管道中的第一个程序正在从终端读取数据,并且您想忽略映射的 EOF,则可以更改终端行为:

stty eof -

并且 Ctrl-D 将不再起作用。或者您可以通过以下方式更改整个生产线规则:

stty raw

并像读取文件一样读取它,无需转换。

您可以使用 EOF 字符发送多个文件,前提是这些文件都不包含该字符。一个 pty 就可以做到。

但是,您可能会更好地使用已建立的解决方案,例如 MIME multipart、zmodem 或归档到管道(例如,这里第二个tar列出了第一个归档的文件:)tar cf - *txt | tar tf -

答案2

问题是,确实不存在“EOF 条件”这样的东西。按照惯例,返回 0 的读取被解释为文件末尾,但正如您所看到的,您可以继续读取。额外的读取可能会再次返回 0,或者如果其他进程同时写入该文件,则它们可以返回更多数据。

甚至Ctrl-D来自终端的信号也不具有特殊的“EOF”信令属性。它真正做的是将当前行输入返回到进程,就像按 Enter 键一样,但区别在于不附加换行符。如果按 Ctrl-D 作为一行(即空行)上的第一个输入,则返回零个字符,这再次按照惯例被解释为“EOF”。

如何解释 read 的返回值 0 由调用 read 系统调用的进程决定。

相关内容