Cでは、ソケットを閉じると、そのソケットが破壊されて後で再利用できることを意味します。
シャットダウンはどうですか?その記述はそのソケットへの二重接続の半分を閉じると言いました。しかし、そのソケットはclose
システムコールのように破壊されますか?
これはBeejのネットワーキングガイドの 説明 です。 shutdown
は、一方向または双方向の通信をブロックするための柔軟な方法です。 2番目のパラメータがSHUT_RDWR
の場合、送信と受信の両方をブロックします(close
のように)。しかし、close
は実際にソケットを破壊する方法です。
shutdown
を使用しても、ピアがすでに送信した保留中のデータを受信することができます(これに注目してくれたJoey Adamsに感謝)。
shutdown
とclose
がTCPプロトコルレベルでどのように機能するかを既存の回答のどれも人々に教えていないので、これを追加する価値があります。
標準のTCP接続は4方向のファイナライズで終了します。
ただし、TCP接続を閉じるには、もう1つ「緊急」の方法があります。
Wiresharkを使った私のテストでは、デフォルトのソケットオプションで、shutdown
がもう一方の端にFINパケットを送信しますが、それがすべてです。相手があなたにFINパケットを送信するまで、あなたはまだデータを受信することができます。これが起こると、あなたのReceive
は0サイズの結果を得るでしょう。ですから、あなたが最初に "send"をシャットダウンするのであれば、データの受信が終わったらソケットを閉じるべきです。
一方、接続がまだアクティブなときにclose
を呼び出すと(もう一方がアクティブで、システムバッファに未送信データがある可能性があります)、RSTパケットが反対側に送信されます。これはエラーに適しています。たとえば、相手が間違ったデータを提供した、またはデータの提供を拒否したと考えられる場合(DOS攻撃は?)、ソケットをすぐに閉じることができます。
私の規則に対する意見は次のようになります。
shutdown
の前にclose
を考慮してくださいSHUT_RDとSHUT_WRのための理想的な実装
次のものはテストされていません、あなた自身の責任で信頼してください。しかし、これは合理的かつ実用的な方法です。
TCPスタックがSHUT_RDのみでシャットダウンを受信した場合、それ以上このデータに接続されているとマークされます。保留中および後続のread
要求(それらがどのスレッドであるかにかかわらず)は、サイズがゼロの結果で返されます。ただし、接続はまだアクティブで使用可能です。たとえば、OOBデータを受信することはできます。また、OSはこの接続に関して受信したデータをすべてドロップします。しかしそれだけで、パッケージは反対側に送信されません。
TCPスタックがSHUT_WRのみでシャットダウンを受信した場合、それ以上のデータを送信できないようにこの接続にマークを付けます。保留中の書き込み要求はすべて終了しますが、それ以降の書き込み要求は失敗します。さらに、送信するデータがないことを知らせるために、FINパケットが別の側に送信されます。
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
それ以上の送受信はできません
これはプラットフォーム固有のものかもしれませんが、どうやら私が見た最も良い説明は ここのmsdnページにあります シャットダウン、残りのオプション、ソケットの閉鎖、一般的な接続終了シーケンスについて説明します。 。
まとめると、shutdownを使用してTCPレベルでシャットダウンシーケンスを送信し、closeを使用してプロセス内のソケットデータ構造体によって使用されているリソースを解放します。 closeを呼び出すまでに明示的なシャットダウンシーケンスを発行していない場合は、自動的にシャットダウンが開始されます。
"shutdown()は実際にはファイルディスクリプタを閉じません - それは使いやすさを変えるだけです。ソケットディスクリプタを解放するには、close()を使う必要があります。" 1
私はまたあるLinuxでshutdown()
で現在ブロックされている別のpthreadを早めに中止させるために1つのpthreadからconnect()
を使うことで成功しました。
他のOS(少なくともOSX)では、close()
を呼び出すだけでconnect()
が失敗するのに十分であることがわかりました。
閉じる
ソケットを使い終わったら、closeでそのファイル記述子を単純に閉じることができます。接続を介して送信されるのを待っているデータがまだある場合、通常closeはこの送信を完了しようとします。タイムアウト期間を指定するには、SO_LINGERソケットオプションを使用してこの動作を制御できます。ソケットオプションを参照してください。
シャットダウン
Shutdownを呼び出して、接続上の受信または送信のみをシャットダウンすることもできます。
シャットダウン機能はソケットの接続をシャットダウンします。その引数howは、実行するアクションを指定します。0このソケットに対するデータの受信を停止します。さらにデータが届いた場合は、それを拒否します。 1このソケットからデータを送信しようとするのをやめます。送信待ちのデータはすべて破棄してください。既に送信されたデータの確認を探すのをやめる。紛失した場合は再送信しないでください。 2受信と送信の両方を停止します。
戻り値は成功すれば0、失敗すれば-1です。
私のテストで。
ソケットが他のプロセスと共有されていない場合、close
は直ちにfinパケットを送信し、fdを破棄します。
shutdown
SHUT_RD、プロセスはソケットからデータを受け取ることができますが、TCPバッファが空の場合、recv
は0を返します。ピアがさらにデータを送信した後recv
は再びデータを返します。
shutdown
SHUT_WRそれ以上の送信が許可されていないことを示すためにfinパケットを送信します。ピアはデータを受信できますが、TCPバッファが空の場合は0を受信します。
shutdown
SHUT_RDWR(SHUT_RDとSHUT_WRの両方を使用するのと同じ)は、ピアがさらにデータを送信すると最初のパケットを送信します。