3

データを受信するために、次のコード スニペットを使用してサーバー クライアント プログラムを作成しています。

    ret_l = select(readfds+1, &readfds, NULL,  NULL ,NULL);
    if(ret_l != -1)
    {
        if(FD_ISSET(myfd, &readfds))
        {
             ret_l = recv(myfd, buf, size_of_buf_array, 0);
             if(ret_l == -1)
                 return ;
         }
    }

私が知る限り、select() されたファイル記述子の recv は、必ずデータを受け取るはずです。しかし、私のコードの recv はエラー ETIMEDOUT で失敗します。なぜこうなったのか誰か教えてください。また、ETIMEDOUT後もデータを完全に受信するための回避策を教えてください。

4

5 に答える 5

7

が表示される理由として、次の 3 つが考えられETIMEDOUTます。

  1. 内部で接続がタイムアウトしましたrecv。これが 1 回も発生する可能性はほとんどありません (ただし、複数回発生することはありません)。
  2. の成功をチェックしなかったためconnect、接続が正常に確立されませんでした (ファイアウォールが接続試行を破棄している可能性があります)。これが考えられる理由です。
  3. ソケットの実装が壊れています。これはほとんどありません。

select生成しませんETIMEDOUT、のみconnect、および recv可能性があります。まれに、受信するものが何もないときに準備完了を報告することがselectありますが (古い Linux カーネルでは、これはおそらく修正されています)、この場合に発生する唯一のことはrecvブロッキングです。

recvこのエラーが発生する可能性がありますが、確立された接続がタイムアウトになる可能性はほとんどありません。ケーブルを引っ張らない場合、または nos が指摘したように、NAT ゲートウェイが何もしないで数分後にタイムアウトする可能性があります。接続が確立できた場合、ルートがあり、誰かが相手側でリッスンしているため、通常、タイムアウトの通常の理由はありません (もちろん、常に発生する可能性はありませんが、タイムアウトが発生する可能性はあります)。もちろん、このエラー、接続が何らかの理由で (ブロックに関係なく) 本当にタイムアウトした場合に最終的に発生しますが、どちらかといえば、通常の状態ではなく、非常に例外的な状態です。

connect失敗は、おそらくさまざまな理由 (到達できない、ファイアウォール、サーバー プロセスが実行されていないなど) によって発生する可能性がある状態であり、それを引き起こす状態である限り、試行するたびに定期的に発生するものです。持続します。

の後にデータを完全に受信するための回避策ETIMEDOUTはありません。readバッファにあるもの(関数呼び出しで指定した最大値まで)を提供するか、ブロックするか、失敗します。これら3つのことのうちの1つで、他には何もありません。
失敗すると、失敗する前に利用できたものはすべてあります (あなたの側で読み取るものは何もありません)。接続は失われます。つまり、ソケットは使用できなくなります。
できることは、新しいソケットを作成して新しい接続を確立し、再試行することだけです。

于 2013-05-27T12:31:34.083 に答える
4

ソケットで TCP キープアライブを有効にすると、 recv ()から ETIMEDOUT errno が返されます。TCP キープアライブは優れたメカニズムであり、必ず確認する必要があります。

ETIMEDOUT は、相手側がしばらくして再送信されたデータを確認しなかった場合、send () によって返される可能性があります。ソケットで ETIMEDOUT errno を引き起こす可能性がある TCP_USER_TIMEOUT ソケット オプションも確認してください。

この章は、有名な本「Unix Network Programming」から確認できます。

于 2016-08-05T15:05:30.057 に答える
0

考えられる理由の 1 つは、ソケット オプションSO_RCVLOWATです。

it の値が 1 より大きい場合、selectof linux は使用可能なバイトが 1 つしかない場合でも戻り、ソケットが読み取り可能であると主張します。

この状況で呼び出すとrecv、タイムアウトが発生する (SO_RCVTIMEO を使用して設定) までブロックされます。これは、利用可能なバイト数が下限値よりも小さいためです。

したがって、コードが の値を変更するかどうかを確認してくださいSO_RCVLOWAT。デフォルト値は 1 です。

詳細:こちら

select(2) および poll(2) システム コールは現在、Linux の SO_RCVLOWAT 設定を尊重せず、1 バイトのデータでも利用可能な場合にソケットを読み取り可能としてマークします。ソケットからの後続の読み取りは、SO_RCVLOWAT バイトが使用可能になるまでブロックされます。

于 2013-05-27T12:28:49.043 に答える
0

勝手な推測です。TCP 接続が失われたとき。select戻り、この fd を読み取り可能に設定します。ただしrecv、エラー ETIMEDOUT で失敗します。

于 2013-05-27T12:20:02.307 に答える