回答:
これは、Beejのネットワーキングガイドで説明されています。 shutdown
一方向または双方向の通信をブロックする柔軟な方法です。2番目のパラメータがの場合、SHUT_RDWR
送信と受信の両方をブロックします(などclose
)。しかしながら、close
実際にソケットを破棄する方法です。
を使用shutdown
すると、ピアがすでに送信した保留中のデータを引き続き受信できます(これを指摘してくれたJoey Adamsに感謝します)。
shutdown
両方向を使用したいが、を使用してソケットへの参照をclose
作成したかどうかが理由の1つです。あなたの場合はソケット、新しくオープンしたファイルは、同じFDを割り当てることができ、そしてその後の使用が非常に悪い可能性が間違った場所を書き込み/読み込みます。だけの場合、後続のを使用すると、が呼び出されるまでエラーが発生します。FILE
fdopen
close
FILE
shutdown
FILE
fclose
shutdown
。ピアにEOFを通知し、ピアが送信した保留中のデータを引き続き受信できるようにするためです。
既存の回答はどれshutdown
もclose
、TCPプロトコルレベルでどのように機能するかをユーザーに伝えないため、これを追加する価値があります。
標準のTCP接続は、4方向のファイナライズによって終了します。
ただし、TCP接続を閉じるには別の「緊急」の方法があります。
Wiresharkを使用した私のテストでは、デフォルトのソケットオプションを使用して、shutdown
FINパケットをもう一方の端に送信しますが、それだけです。相手がFINパケットを送信するまで、データを受信できます。これが発生するReceive
と、サイズは0になります。したがって、「送信」を最初にシャットダウンする場合は、データの受信が終了したらソケットを閉じる必要があります。
一方、 close
一方、接続がアクティブな間に(反対側はまだアクティブであり、システムバッファーに未送信のデータがある場合もあります)、RSTパケットが反対側に送信されます。これはエラーに適しています。たとえば、相手が間違ったデータを提供した、またはデータの提供を拒否した(DOS攻撃?)と思われる場合は、すぐにソケットを閉じることができます。
ルールについての私の意見は:
shutdown
事前close
に検討するSHUT_RDおよびSHUT_WRの理想的な実装
以下はテストされていません。自己責任で信頼してください。ただし、これは合理的で実用的な方法です。
TCPスタックがSHUT_RDのみでシャットダウンを受信した場合、TCPスタックは、この接続に予期されるデータがないとマークします。保留中のread
リクエストと後続のリクエストは(どのスレッドにあるかに関係なく)、サイズがゼロの結果で返されます。ただし、接続はまだアクティブで使用可能です-たとえば、OOBデータを引き続き受信できます。また、OSはこの接続で受信したデータをすべてドロップします。しかし、それだけです。パッケージは反対側に送信されません。
TCPスタックがSHUT_WRのみでシャットダウンを受信した場合、これ以上データを送信できないため、この接続にマークを付けます。保留中の書き込み要求はすべて終了しますが、後続の書き込み要求は失敗します。さらに、FINパケットが別の側に送信され、送信するデータがないことを通知します。
shutdown()
は接続をすることができ、それからそれはもはや生きていません。まだファイル記述子があります。まだrecv()
受信バッファーからできます。またclose()
、ファイル記述子を破棄するために呼び出す必要があります。
代わりにclose()
使用すれば回避できるいくつかの制限がありますshutdown()
。
close()
TCP接続で双方向を終了します。他のエンドポイントにデータの送信が終了したことを伝えたいが、それでもデータを受信したい場合があります。
close()
記述子参照カウント(ファイルテーブルエントリに保持され、ファイル/ソケットを参照している現在開いている記述子の数をカウントします)をデクリメントし、記述子が0でない場合はソケット/ファイルを閉じません。これは、フォークしている場合、クリーンアップは、参照カウントが0になった後にのみ行われshutdown()
ます。参照カウントを無視して、通常のTCPクローズシーケンスを開始できます。
パラメータは次のとおりです。
int shutdown(int s, int how); // s is socket descriptor
int how
次のいずれかになります。
SHUT_RD
またはそれ0
以上の受信は許可されていません
SHUT_WR
またはそれ1
以上の送信は許可されていません
SHUT_RDWR
またはそれ2
以上の送受信は許可されていません
これはプラットフォーム固有の可能性がありますが、どういうわけか疑いますが、とにかく、私が見た最良の説明は、このmsdnページにあり、シャットダウン、残存オプション、ソケットクロージャ、および一般的な接続終了シーケンスについて説明しています。
要約すると、shutdownを使用してTCPレベルでシャットダウンシーケンスを送信し、closeを使用してプロセスのソケットデータ構造で使用されているリソースを解放します。closeを呼び出すまでに明示的なシャットダウンシーケンスを発行していない場合は、シャットダウンシーケンスが開始されます。
「shutdown()は実際にはファイル記述子を閉じません。それは、その使いやすさを変更するだけです。ソケット記述子を解放するには、close()を使用する必要があります。」1
閉じる
ソケットの使用が終了したら、closeを使用してファイル記述子を閉じるだけです。接続を介して送信されるのを待っているデータがまだある場合、通常、closeはこの送信を完了しようとします。SO_LINGERソケットオプションを使用してこの動作を制御し、タイムアウト期間を指定できます。ソケットオプションを参照してください。
シャットダウン
また、shutdownを呼び出して、接続の受信または送信のみをシャットダウンすることもできます。
シャットダウン機能は、ソケットの接続をシャットダウンします。その引数howは、実行するアクションを指定します。0このソケットのデータの受信を停止します。さらにデータが到着した場合は、それを拒否します。1このソケットからのデータ送信の試行を停止します。送信を待機しているデータを破棄します。すでに送信されたデータの確認を探すのをやめます。紛失した場合は再送信しないでください。2受信と送信の両方を停止します。
戻り値は、成功した場合は0、失敗した場合は-1です。
私のテストでは。
close
ソケットが他のプロセスと共有されていない場合、finパケットを送信し、fdを即座に破棄します
shutdown
SHUT_RD、プロセスは引き続きソケットからデータを受信できますが、recv
TCPバッファーが空の場合は0 recv
を返します。ピアがさらにデータを送信した後、再びデータを返します。
shutdown
SHUT_WRは、finパケットを送信して、それ以上の送信が許可されていないことを示します。ピアはデータを受信できますが、TCPバッファが空の場合は0を受信します
shutdown
SHUT_RDWR(SHUT_RDとSHUT_WRの両方を使用するのと同じ)は、ピアがさらにデータを送信する場合、最初のパケットを送信します。
close()
、FINの代わりにLinuxでRST を送信しました。
recv()
再びデータを返します」は正しくありません。2.ピアが後にさらにデータを送信する場合の動作SHUT_RD
は、プラットフォームに依存します。