2017-04-10 7 views
0

パイプからデータを受け取っているときにstdinで使用されたときのselect()の振る舞いについての理解を理解しようとしています。パイプ上で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); 
} 

私はエコー文字を見ることができました。キーを押さないと、「No Data」と表示されます。

./hello 

ただし、プログラムを次のように使用すると、プログラムは「データなし」と表示されることはありません。代わりに最後の文字「c」が繰り返し表示されます。

echo -n abc | ./hello 

私はこの観察に困惑し、観察された動作を理解するのを助けることができれば感謝します。

答えて

0

問題は、STDIN_FILENO記述子から読み取ったときにプログラムがファイルの終わりの状態を検出しないことです。 echoの後にc文字が書き込まれると、パイプの終わりが閉じられ、プログラム内のselectがすぐに返され、readは、そのディスクリプタからデータがこれ以上利用できなくなることを示す0として返されます。あなたのプログラムはその状態を検出しません。代わりに、最後に成功したreadによってバッファに残された文字でwriteを呼び出してから、ループを繰り返します。

修正するには、readの後にif (n==0) break;を実行します。

+0

ありがとうございました。これは、fdが閉じたファイルを参照するときにselect()がエラー条件(-1)を返さないことを意味しますか? – ubndra

+0

記述子のいずれかが閉じたファイルを参照する場合、 'select'は-1を返します。あなたのプログラムのSTDIN記述子を決して閉じないので、あなたのプログラムでは起こりません。 'read'が0を返すときに' close(STDIN_FILENO) 'を実行してループの中にいれば、次の' select'呼び出しから-1が表示されます。 ( 'echo'プログラムでパイプの書き込み側で実行される' close'は、プログラム内のパイプの読み込み側を閉じません。プログラム内の 'read'に対する 'end of file' 。) – ottomeister

関連する問題