3

更新:コードと問題の説明を更新して、変更を反映させました。

非ソケットでソケット操作を試みていることがわかりました。または、次の理由で fd_set が無効であること:

select-1 を WSAGetLastError()返し、10038 を返します。

しかし、私はそれが何であるかを理解できないようです。プラットフォームは Windows です。その部分は掲載していませんWSAStartup

int loop = 0;
FILE *output

int main()
{
    fd_set fd;
    output = _popen("tail -f test.txt","r");

    while(forceExit == 0)
    {   
        FD_ZERO(&fd);
        FD_SET(_fileno(output),&fd);

        int returncode = select(_fileno(output)+1,&fd,NULL,NULL,NULL);
        if(returncode == 0)
        {
            printf("timed out");
        }
        else if (returncode < 0)
        {
            printf("returncode: %d\n",returncode);
            printf("Last Error: %d\n",WSAGetLastError());
        }
        else
        {
            if(FD_ISSET(_fileno(output),&fd))
            {
                if(fgets(buff, sizeof(buff), output) != NULL )
                {               
                    printf("Output: %s\n", buff);
                }
            }
            else
            {
                printf(".");
            }
        }
        Sleep(500);
    }
    return 0;
}

新しい結果はもちろん、リターンコードと最後のエラーの出力です。

4

7 に答える 7

3

読み取る準備ができているデータがいくつかありますが、実際には何も読み取っていません。次回記述子をポーリングするとき、データはまだそこにあります。ポーリングを続行する前に、パイプを排水してください。

于 2008-09-30T13:01:49.270 に答える
1

まず第一に、あなたと他の人が指摘したように、select()Windows のソケットに対してのみ有効です。返さselect()れるストリームでは機能しません。_popen()エラー 10038 は、これを明確に識別します。

あなたの例の目的がわかりません。単純にプロセスを生成して stdout を収集したい場合は、次のようにします (MSDN _popen ページから直接取得します)。

int main( void )
{

   char   psBuffer[128];
   FILE   *pPipe;

   if( (pPipe = _popen("tail -f test.txt", "rt" )) == NULL )
      exit( 1 );

   /* Read pipe until end of file, or an error occurs. */

   while(fgets(psBuffer, 128, pPipe))
   {
      printf(psBuffer);
   }


   /* Close pipe and print return value of pPipe. */
   if (feof( pPipe))
   {
     printf( "\nProcess returned %d\n", _pclose( pPipe ) );
   }
   else
   {
     printf( "Error: Failed to read the pipe to the end.\n");
   }
}

それでおしまい。選択不要。

ここでスレッドがどのように役立つかはわかりません。これは問題を複雑にするだけです。

于 2008-10-02T00:47:26.883 に答える
1

私が知る限り、Windows の匿名パイプは、select のような非ブロッキング呼び出しでは使用できません。そのため、_popen と select のコードは独立しているように見えますが、2 つを結合することはできません。

他の場所にも同様のスレッドがあります。

PIPE_NOWAIT フラグを指定してSetNamedPipeHandleStateを呼び出すとうまくいく可能性がありますが、MSDN はこの件に関して少し難解です。

したがって、これを達成するための他の方法を検討する必要があると思います。別のスレッドで読み取りを行い、通常のブロッキング I/O を使用することをお勧めします。

于 2008-09-30T15:32:23.373 に答える
0
  1. select()最初の引数は、セット内の最大数のファイル記述子に1を加えたものです(つまり、output + 1)

    select(output + 1、&fd、NULL、&exceptfds、NULL);

  2. 最初はfdFD_ISSET(...)にあるはずです。fd_set

    if(FD_ISSET(filePointer、&fd))

  3. データストリームにデータがある場合は、そのデータストリームを読み取る必要があります。データソースから読み取るには、fgets(...)などを使用します。

    char buf [1024]; ... fgets(buf、sizeof(buf)* sizeof(char)、output);

于 2008-09-30T13:31:12.743 に答える
0

私が最初に間違っていることに気付くのは、各条件で exceptfds に対して FD_ISSET を呼び出していることです。私はあなたがこのようなものが欲しいと思います:

if (FD_ISSET(filePointer,&fd))
{
    printf("i have data\n");
}
else ....

select の except フィールドは、通常、ソケットのエラーまたは帯域外データを報告するために使用されます。例外の記述子の 1 つが設定されている場合、それは必ずしもエラーを意味するのではなく、何らかの「メッセージ」(つまり、帯域外データ) を意味します。あなたのアプリケーションでは、ファイル記述子を例外セットの中に入れなくてもおそらくうまくいくと思います。本当にエラーをチェックしたい場合は、select の戻り値をチェックし、-1 (または Windows では SOCKET_ERROR) が返された場合に何かを行う必要があります。お使いのプラットフォームがわからないため、リターン コードについてこれ以上具体的に説明することはできません。

于 2008-09-30T12:44:00.767 に答える
0

機能しselectないため、スレッド、具体的_beginthreadには_beginthreadex.

于 2008-10-01T14:46:00.963 に答える
0

選択する最初の引数は、3 つのセットのいずれかで最大の番号のファイル記述子に 1 を加えたものである必要があります。

   int select(int nfds, fd_set *readfds, fd_set *writefds,
              fd_set *exceptfds, struct timeval *timeout);

また:

    if(FD_ISSET(filePointer,&exceptfds))
    {
            printf("i have data\n");
    }

次のようにする必要があります。

    if(FD_ISSET(filePointer,&fd))
    {
            printf("i have data\n");
    }

select() からの戻りコードを確認する必要があります。

また、select() を呼び出すたびに fdsets をリセットする必要があります。

使用していないため、タイムアウトは必要ありません。

編集:

どうやら Windows では nfds は無視されますが、コードの移植性を高めるために、おそらく正しく設定する必要があります。

タイムアウトを使用する場合は、最後の引数として select 呼び出しに渡す必要があります。

// Reset fd, exceptfds, and timeout before each select()...
int result = select(maxFDPlusOne, &fd, NULL, &exceptfds, &timeout);

if (result == 0)
{
    // timeout
}
else if (result < 0)
{
    // error
}
else
{
    // something happened
    if (FD_ISSET(filePointer,&fd))
    {
        // Need to read the data, otherwise you'll get notified each time.
    }
}
于 2008-09-30T12:32:08.017 に答える