C - select() 在 stdin 上,当 stdin's 缓冲区中已经有数据时



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()了,但我正在为考试而学习,我们必须…)

从根本上说,问题是您将缓冲的stdio流与低级别I/O混合在一起。select被阻塞的原因是先前键入的数据已经被读取,并且被缓冲在stdin的流数据缓冲区中。尝试通过调用setbuf(stdin, NULL)stdin设置为无缓冲模式。

您正在读取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

最新更新