c-select()响应stdin,但不响应/dev/tty



这是一个非常类似的问题,select((似乎在TTY上不起作用,但我在FD_SET和OP上似乎没有犯同样的错误。

在我的Linux盒子(运行Ubuntu 20.04 LTS for Desktop(上,我试图在阻塞模式(无条件调用fgetc()(和非阻塞模式(反复询问select()是否值得调用fgetc()(下从控制台读取一个未缓冲的字符。

如果我在读stdin,这两种模式都能工作。然而,如果我想从控制台显式读取stdin,而不考虑是否已重定向,我的理解是应该打开"/dev/tty"。这也适用于阻塞模式,但不适用于非阻塞模式:尽管疯狂按键,select()在每次超时结束时仍保持返回0。我不知道为什么stdin/dev/tty在这方面会有不同的表现。他们的termios标志似乎是一样的。

$ gcc foo.c
$ ./a.out
c_iflag = 25862
c_oflag = 5
c_cflag = 191
c_lflag = 35387
Well?? 
read character 'g' in blocking mode from stdin
We're waiting... 0 0 
read character 'g' in non-blocking mode from stdin
$ ./a.out /dev/tty
c_iflag = 25862
c_oflag = 5
c_cflag = 191
c_lflag = 35387
Well?? 
read character 'g' in blocking mode from /dev/tty
We're waiting... 0 0 0 0 0 0 0 0 0 0 
too slow: read nothing in non-blocking mode from /dev/tty
$ ggggggggggg

如果我尝试使用/dev/console/dev/tty0,我只是失败了,fopen()中的FILE *为空。这是源foo.c。我错过了什么?

#include <stdio.h>
#include <sys/select.h>
#include <termios.h>
int main( int argc, const char * argv[] )
{

const char * name = "stdin";
FILE * filePointer = stdin;
int fileDescriptor;
struct timeval timeout;
struct termios term;
fd_set rdset;
int result, iCycle, nCycles = 10;
char c;
if( argc > 1 ) /* open the user-specified file instead of stdin */
{
name = argv[ 1 ];
filePointer = fopen( name, "r" );
}
if( !filePointer ) return fprintf( stderr, "failed to open %s", name );

fileDescriptor = fileno( filePointer );
/* make things unbuffered, non-canonical, non-echoey */
setvbuf( filePointer, NULL, _IONBF, 0 );
tcgetattr( fileDescriptor, &term );
printf("c_iflag = %dn", term.c_iflag);
printf("c_oflag = %dn", term.c_oflag);
printf("c_cflag = %dn", term.c_cflag);
printf("c_lflag = %dn", term.c_lflag);
term.c_lflag &= ~ICANON;
term.c_lflag &= ~ECHO;
tcsetattr( fileDescriptor, TCSANOW, &term );

/* get an unbuffered character (blocking mode) */
fprintf( stdout, "nWell?? " );
fflush( stdout );
c = fgetc( filePointer );
fprintf( stdout, "nread character '%c' in blocking mode from %sn", c, name );
fflush( stdout );
/* get an unbuffered character (non-blocking mode) */
fprintf( stdout, "nWe're waiting... " );
fflush( stdout );
for( iCycle = 0; iCycle < nCycles; iCycle++ )
{
FD_ZERO( &rdset );
FD_SET( fileDescriptor, &rdset );
timeout.tv_sec  = 1;
timeout.tv_usec = 0;
result = select( 1, &rdset, NULL, NULL, &timeout );
if( result > 0 ) break;
fprintf( stdout, "%d ", result );
fflush( stdout );
if( result > 0 ) break;
}
if( iCycle < nCycles )
{
c = fgetc( filePointer );
fprintf( stdout, "nread character '%c' in non-blocking mode from %sn", c, name );
fflush( stdout );
}
else
{
fprintf( stdout, "ntoo slow: read nothing in non-blocking mode from %sn", name );
fflush( stdout );
}

/* restore canonicality (avoid having to type `reset` after every run) */
term.c_lflag |= ICANON;
term.c_lflag |= ECHO;
tcsetattr( fileDescriptor, TCSANOW, &term );
if( filePointer != stdin ) fclose( filePointer );
return 0;
}

问题是select()的第一个参数。CCD_ 18仅检查每个FD集合中的第一个CCD_。由于指定了1,因此它只检查FD 0上的输入,而忽略用于/dev/tty的FD。

更改为:

select(fileDescriptor+1, &rdset, NULL, NULL, &timeout );

最新更新