C – stdin缓冲区中已有数据时,在stdin上选择()
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 #include #include #include 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() failed\n"); } if(FD_ISSET(fileno(stdin), &rfds)) { printf("Keyboard input received: "); fgets(buf, 5, stdin); printf("%s\n", 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
设置为无缓冲模式。