当标准输入缓冲区中已有数据时,在标准输入上选择()

select函数阻塞调用进程,直到在任何指定的文件描述符集上有活动[...]如果读取调用不会阻塞,则认为文件描述符已准备好可供读取。 (请参阅:https://www.gnu.org/software/libc/manual/html_node/Waiting-for-I_002fO.html)

所以我期望,如果在第一次迭代中输入大于4个字符的字符串,那么在下面的程序中选择将立即返回第二个...迭代。 但事实并非如此。 在第一个输出后按任何其他键后,它将继续处理所有剩余的输入。 为什么?

示例输出:

./selectTest
12345678900
Keyboard input received: 1234
A
Keyboard input received: 5678
Keyboard input received: 900

Keyboard input received: A

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

int main(void)
{
    fd_set rfds;
    char buf[100];

    while(1)
    {
        FD_ZERO(&rfds);       
        FD_SET(fileno(stdin), &rfds);

        if(-1 == select(FD_SETSIZE, &rfds, NULL, NULL, NULL))
        {
            perror("select() failedn");
        }

        if(FD_ISSET(fileno(stdin), &rfds)) 
        {
            printf("Keyboard input received: ");
            fgets(buf, 5, stdin);
            printf("%sn", buf);
        }
    }
    return 0;
}

(我知道,我不应该再使用select(),但我正在学习考试,我们必须......)


你正在阅读tty(4)(通常情况下,当stdin是你的终端时)。 这些都是棘手的事情,阅读tty揭秘。

请注意,你的终端和它的tty有一些线性规则。 所以,一些数据在内核中(也在标准库中)被缓冲。

您可能想要将您的tty置于原始模式。 参见termios(3)&stty(1)

但不要失去时间,而应使用像ncurses或readline这样的库

要使用select ,你可以使用一些fifo(7),也许使用mkfifo /tmp/myfifo然后使用你的程序yourprogram < /tmp/myfifo并在另一个终端中使用echo hello > /tmp/myfifo


基本上,问题在于你将缓冲的stdio流与低级I / O混合在一起。 select被阻塞的原因是因为之前输入的数据已被读取并被缓存在stdin的流数据缓冲区中。 尝试通过调用setbuf(stdin, NULL)stdin设置为无缓冲模式。

链接地址: http://www.djcxy.com/p/68803.html

上一篇: select() on stdin when there is already data in stdin's buffer

下一篇: C stdio unbuffered multiplexing