2011-06-24 19 views
1

クライアントが100バイトのデータを送信したとしますが、何らかの理由でサーバが90バイトしか受信しなかったとします。このケースをどうやって処理するのですか?サーバが受信中のデータをチェックしている間に "read"関数を呼び出すと、サーバは最後の10バイトを永久に待機します。epoll()を使用した短い読み込みの処理

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

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

答えて

1

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

通常の場合、ループはread()で終わり、errnoEAGAINに設定して-1を返します。これは、接続が閉じられていないことを示しますが、現在のデータはそれ以上使用できません。この時点で、クライアントからのデータがまだ不足している場合は、のデータを保存してから、のデータを保存して、メインのepoll()ループに戻すだけです。

残りのデータが到着すると、ソケットはepoll()で読み取り可能な状態で返され、残りのデータはread()となり、保存されたデータを再度処理して処理します。

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

1

戻り値readを慎重にチェックする必要があります。 3つののいずれかを返すことができます。

いくつかのバイトが読み取られたことを示す正の数です。

ゼロは、相手側が接続を正常に閉じたことを示します。

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

あなたのコードがこれらの3つの事柄のそれぞれをチェックせず、それらを別々に扱っていないなら、それはほぼ確実に壊れてしまいます。

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

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

0

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

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

0

これは、接続が閉じられているかどうかを判断する唯一の安全な方法であるため、EPOLLRDHUPを購読することをおすすめします(read()== 0は信頼できません)エラーの場合は真となる可能性があります)。 EPOLLERRは、あなたが特に要求していなくても、であり、常にに登録されています。正しい動作は、EPOLLRDHUPの場合はclose()を使用して、おそらくEPOLLERRが設定されている場合でも接続を閉じることです。

詳細については、こちらからも同様の回答を得ました:epoll_wait() receives socket closed twice (read()/recv() returns 0)

関連する問題