select() 在管道上使用时在标准输入上的行为
Behavior of select() on stdin when used on a pipe
我试图理解对 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);
}
如果我 运行 程序如下,当我在程序 运行 上键入按键时,我可以看到字符回显。当不按下键时,它会按预期显示 "No Data"。
./hello
但是,如果如下使用程序,程序永远不会进入显示"No Data"的状态。相反,重复显示最后一个字符 "c"。
echo -n abc | ./hello
我对这个观察有点困惑,如果你能帮助我理解观察到的行为,我将不胜感激。
问题是您的程序在读取 STDIN_FILENO
描述符时没有检测到文件结束条件。在 echo
写入 c
字符后,它将关闭管道的末端,这将导致程序中的 select
立即变为 return 并且 read
到 return 0 表示该描述符不再提供更多数据。您的程序没有检测到该情况。相反,它只是用最后一个成功 read
留在缓冲区中的任何字符调用 write
,然后重复循环。
要修复,请在 read
之后执行 if (n==0) break;
。
我试图理解对 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);
}
如果我 运行 程序如下,当我在程序 运行 上键入按键时,我可以看到字符回显。当不按下键时,它会按预期显示 "No Data"。
./hello
但是,如果如下使用程序,程序永远不会进入显示"No Data"的状态。相反,重复显示最后一个字符 "c"。
echo -n abc | ./hello
我对这个观察有点困惑,如果你能帮助我理解观察到的行为,我将不胜感激。
问题是您的程序在读取 STDIN_FILENO
描述符时没有检测到文件结束条件。在 echo
写入 c
字符后,它将关闭管道的末端,这将导致程序中的 select
立即变为 return 并且 read
到 return 0 表示该描述符不再提供更多数据。您的程序没有检测到该情况。相反,它只是用最后一个成功 read
留在缓冲区中的任何字符调用 write
,然后重复循环。
要修复,请在 read
之后执行 if (n==0) break;
。