我试图理解在stdin上使用时对select()行为的观察,当它从管道接收数据时。
基本上我使用以下代码有一个简单的C程序: 的hello.c:
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <termios.h>
int main(int argc, char *argv[])
{
int flags, opt;
int nsecs, tfnd;
fd_set rfds;
struct timeval tv;
int retval;
int stdin_fileno_p1 = STDIN_FILENO+1;
char c;
int n;
/* Turn off canonical processing on stdin*/
static struct termios oldt, newt;
tcgetattr( STDIN_FILENO, &oldt);
newt = oldt;
newt.c_lflag &= ~(ICANON);
tcsetattr( STDIN_FILENO, TCSANOW, &newt);
while (1)
{
FD_ZERO(&rfds);
FD_SET(STDIN_FILENO, &rfds);
tv.tv_sec = 0;
tv.tv_usec = 0;
retval = select(stdin_fileno_p1, &rfds, NULL, NULL, &tv);
if ( retval && (retval!=-1) )
{
n = read(STDIN_FILENO, &c, 1);
write(STDOUT_FILENO, &c, 1);
}
else printf("No Data\n");
usleep(100000);
}
tcsetattr( STDIN_FILENO, TCSANOW, &oldt);
}
如果我按如下方式运行程序,我可以看到当程序运行时键入键时字符回显。未按下键时,按预期显示“无数据”。
./hello
但是,如果按如下方式使用程序,程序永远不会进入显示“无数据”的状态。而是重复显示最后一个字符“c”。
echo -n abc | ./hello
我对这一观察感到有些困惑,如果你能帮我理解观察到的行为,我将不胜感激。
答案 0 :(得分:0)
问题是,当程序从STDIN_FILENO
描述符中读取时,程序不会检测到文件结束条件。在echo
写入c
字符后,它将关闭管道的末尾,这将导致程序中的select
立即返回,而read
将返回0表明该描述符不再有数据可用。您的程序未检测到该情况。相反,它只是使用上一次成功write
中缓冲区中剩余的任何字符调用read
,然后重复循环。
要解决此问题,请在if (n==0) break;
后执行read
。