1

クライアントが100バイトのデータを送信したが、どういうわけかサーバーは90バイトしか受信しなかったとしましょう。このケースをどのように処理しますか?サーバーがwhileループ内で「読み取り」関数を呼び出して、受信したデータの合計をチェックすると、サーバーはパックの最後の10バイトを永久に待機します。

また、データ転送の途中でクライアントが切断される可能性があります。この場合、サーバーは到着しないすべてのデータを受信するまで永久に待機します。

私はtcpを使用していますが、実際のネットワーク環境では、この状況が発生する可能性があります。前もって感謝します...

4

4 に答える 4

1

の戻り値を注意深く確認する必要がありますread次の3つのいずれかを返すことができます。

一部のバイトが読み取られたことを示す正の数。

ゼロ。もう一方の端が接続を正常に閉じたことを示します。

-1は、エラーが発生したことを意味します。(ソケットが非ブロッキングの場合、エラーEAGAINまたはEWOULDBLOCKは、接続はまだ開いていますが、現在データの準備ができていないことを意味します。したがって、epollさらにデータがあると表示されるまで待つ必要があります。)

コードがこれら3つのことのそれぞれをチェックしておらず、それらを異なる方法で処理していない場合、ほぼ確実に壊れています。

これらは、クライアントが90バイトを送信してから接続を閉じるか、無礼に切断するなど、質問しているすべてのケースをカバーします(これらのケースでは、read()が0または-1を返すため)。

クライアントが90バイトを送信し、それ以上送信せず、接続を閉じないことが心配な場合は、独自のタイムアウトを実装する必要があります。そのための最善の策は、ソケットをブロックせず、select()/ poll()/ epoll()にタイムアウトを設定し、アイドル状態が長すぎる場合は接続を破棄することです。

于 2011-06-24T02:16:13.470 に答える
1

read()必要なバイト数を受け取るまで、ループ内で関数を呼び出さないでください。代わりに、ソケットをノンブロッキングに設定し、(ストリームの終了を示す)またはエラーがread()返されるまでループで関数を呼び出します。0

通常の場合、ループはread()-1を返し、をにerrno設定して終了しEAGAINます。これは、接続が閉じられていないことを示していますが、現時点で利用できるデータはありません。この時点で、クライアントからの十分なデータがまだない場合は、後で使用するために持っているデータを保存しepoll()、メインループに戻るだけです。

残りのデータが到着すると、ソケットはによって読み取り可能として返されepoll()read()残りのデータを取得し、保存されたデータを取得してすべて処理します。

これは、まだ読み取られていないが処理されていないデータを格納するために、ソケットごとのデータ構造にスペースが必要であることを意味します。

于 2011-06-24T05:50:50.983 に答える
0

TCP接続は、パケットベースのネットワークの上に階層化された双方向ストリームです。反対側が送信したものの一部のみを読み取ることはよくあることです。完全なメッセージが得られるまで追加して、ループで読み取る必要があります。そのためには、TCP上で使用するアプリケーションレベルのプロトコル(メッセージのタイプ、構造、およびセマンティクス)が必要です(FTP、HTTP、SMTPなどがそのようなプロトコルです)。

質問の特定の2番目の部分に答えるにはEPOLLRDHUP、一連のepoll(7)イベントに追加して、接続が切断されたときに通知を受け取ります。

于 2011-06-24T02:17:49.613 に答える
0

cafが言ったことに加えて、EPOLLRDHUPをサブスクライブすることをお勧めします。これは、接続が閉じられたかどうかを判断する唯一の安全な方法であるためです(read()== 0は信頼できません。これは、cafもこれに言及しているためです。エラーの場合)。EPOLLERRは、特に要求していなくても、常にサブスクライブされています。正しい動作は、EPOLLRDHUPの場合、およびおそらくEPOLLERRが設定されている場合でも、close()を使用して接続を閉じることです。

詳細については、ここで同様の回答を示しました。epoll_wait()は、ソケットを2回閉じて受信します(read()/ recv()は0を返します)

于 2011-07-20T13:07:25.127 に答える