web-dev-qa-db-ja.com

シャットダウンソケット対閉じる?

Cでは、ソケットを閉じると、そのソケットが破壊されて後で再利用できることを意味します。

シャットダウンはどうですか?その記述はそのソケットへの二重接続の半分を閉じると言いました。しかし、そのソケットはcloseシステムコールのように破壊されますか?

191
user188276

これはBeejのネットワーキングガイドの 説明 です。 shutdownは、一方向または双方向の通信をブロックするための柔軟な方法です。 2番目のパラメータがSHUT_RDWRの場合、送信と受信の両方をブロックします(closeのように)。しかし、closeは実際にソケットを破壊する方法です。

shutdownを使用しても、ピアがすでに送信した保留中のデータを受信することができます(これに注目してくれたJoey Adamsに感謝)。

173

shutdowncloseがTCPプロトコルレベルでどのように機能するかを既存の回答のどれも人々に教えていないので、これを追加する価値があります。

標準のTCP接続は4方向のファイナライズで終了します。

  1. 参加者が送信するデータがなくなると、参加者はもう一方にFINパケットを送信します。
  2. 相手側はFINに対してACKを返します。
  3. 相手方もデータ転送を終了すると、別のFINパケットを送信します
  4. 最初の参加者はACKを返し、転送を終了します。

ただし、TCP接続を閉じるには、もう1つ「緊急」の方法があります。

  1. 参加者がRSTパケットを送信して接続を放棄する
  2. 相手側はRSTを受信して​​から接続も放棄します

Wiresharkを使った私のテストでは、デフォルトのソケットオプションで、shutdownがもう一方の端にFINパケットを送信しますが、それがすべてです。相手があなたにFINパケットを送信するまで、あなたはまだデータを受信することができます。これが起こると、あなたのReceiveは0サイズの結果を得るでしょう。ですから、あなたが最初に "send"をシャットダウンするのであれば、データの受信が終わったらソケットを閉じるべきです。

一方、接続がまだアクティブなときにcloseを呼び出すと(もう一方がアクティブで、システムバッファに未送信データがある可能性があります)、RSTパケットが反対側に送信されます。これはエラーに適しています。たとえば、相手が間違ったデータを提供した、またはデータの提供を拒否したと考えられる場合(DOS攻撃は?)、ソケットをすぐに閉じることができます。

私の規則に対する意見は次のようになります。

  1. 可能であればshutdownの前にcloseを考慮してください
  2. シャットダウンする前に(サイズ0のデータを受信して​​)受信を終了した場合は、最後の送信(もしあれば)が終了した後で接続を閉じます。
  3. 接続を正常に閉じたい場合は(SHUT_WRを使用し、この時点以降にデータを受信する必要がない場合はSHUT_RDを使用して)接続をシャットダウンし、サイズが0のデータを受信するまで待ってから閉じます。ソケット。
  4. いずれにせよ、他のエラー(タイムアウトなど)が発生した場合は、ソケットを閉じてください。

SHUT_RDとSHUT_WRのための理想的な実装

次のものはテストされていません、あなた自身の責任で信頼してください。しかし、これは合理的かつ実用的な方法です。

TCPスタックがSHUT_RDのみでシャットダウンを受信した場合、それ以上このデータに接続されているとマークされます。保留中および後続のread要求(それらがどのスレッドであるかにかかわらず)は、サイズがゼロの結果で返されます。ただし、接続はまだアクティブで使用可能です。たとえば、OOBデータを受信することはできます。また、OSはこの接続に関して受信したデータをすべてドロップします。しかしそれだけで、パッケージは反対側に送信されません。

TCPスタックがSHUT_WRのみでシャットダウンを受信した場合、それ以上のデータを送信できないようにこの接続にマークを付けます。保留中の書き込み要求はすべて終了しますが、それ以降の書き込み要求は失敗します。さらに、送信するデータがないことを知らせるために、FINパケットが別の側に送信されます。

116
Earth Engine

close()にはいくつかの制限がありますが、代わりにshutdown()を使用する場合は回避できます。

close()はTCP接続で両方向を終了します。他のエンドポイントにデータの送信は終了したが、それでもデータを受信したいことを伝えたい場合があります。

close()はディスクリプタの参照カウント(ファイルテーブルエントリに保持され、ファイル/ソケットを参照している現在開いているディスクリプタの数をカウント)を減らし、ディスクリプタが0でなければソケット/ファイルを閉じません。 shutdown()を使うと、参照カウントを無視して通常のTCPクローズシーケンスを開始することができます。

パラメータは次のとおりです。

int shutdown(int s, int how); // s is socket descriptor

int howは次のようになります。

SHUT_RDまたは0それ以上の受信は許可されていません

SHUT_WRまたは1それ以上の送信は許可されていません

SHUT_RDWRまたは2それ以上の送受信はできません

35
Milan

これはプラットフォーム固有のものかもしれませんが、どうやら私が見た最も良い説明は ここのmsdnページにあります シャットダウン、残りのオプション、ソケットの閉鎖、一般的な接続終了シーケンスについて説明します。 。

まとめると、shutdownを使用してTCPレベルでシャットダウンシーケンスを送信し、closeを使用してプロセス内のソケットデータ構造体によって使用されているリソースを解放します。 closeを呼び出すまでに明示的なシャットダウンシーケンスを発行していない場合は、自動的にシャットダウンが開始されます。

15
Len Holgate

"shutdown()は実際にはファイルディスクリプタを閉じません - それは使いやすさを変えるだけです。ソケットディスクリプタを解放するには、close()を使う必要があります。" 1

私はまたあるLinuxでshutdown()で現在ブロックされている別のpthreadを早めに中止させるために1つのpthreadからconnect()を使うことで成功しました。

他のOS(少なくともOSX)では、close()を呼び出すだけでconnect()が失敗するのに十分であることがわかりました。

7
Toby

閉じる

ソケットを使い終わったら、closeでそのファイル記述子を単純に閉じることができます。接続を介して送信されるのを待っているデータがまだある場合、通常closeはこの送信を完了しようとします。タイムアウト期間を指定するには、SO_LINGERソケットオプションを使用してこの動作を制御できます。ソケットオプションを参照してください。

シャットダウン

Shutdownを呼び出して、接続上の受信または送信のみをシャットダウンすることもできます。

シャットダウン機能はソケットの接続をシャットダウンします。その引数howは、実行するアクションを指定します。0このソケットに対するデータの受信を停止します。さらにデータが届いた場合は、それを拒否します。 1このソケットからデータを送信しようとするのをやめます。送信待ちのデータはすべて破棄してください。既に送信されたデータの確認を探すのをやめる。紛失した場合は再送信しないでください。 2受信と送信の両方を停止します。

戻り値は成功すれば0、失敗すれば-1です。

3
Neha Agrawal

私のテストで。

ソケットが他のプロセスと共有されていない場合、closeは直ちにfinパケットを送信し、fdを破棄します。

shutdownSHUT_RD、プロセスはソケットからデータを受け取ることができますが、TCPバッファが空の場合、recvは0を返します。ピアがさらにデータを送信した後recvは再びデータを返します。

shutdownSHUT_WRそれ以上の送信が許可されていないことを示すためにfinパケットを送信します。ピアはデータを受信できますが、TCPバッファが空の場合は0を受信します。

shutdownSHUT_RDWRSHUT_RDSHUT_WRの両方を使用するのと同じ)は、ピアがさらにデータを送信すると最初のパケットを送信します。

1
simpx