LPWSPCLOSESOCKET
コールバックシグネチャ
INT LPWSPCLOSESOCKET(
SOCKET s,
INT* lpErrno
);パラメーター
| フィールド | 型 | 説明 |
|---|---|---|
| s | SOCKET | ソケットを識別するディスクリプター。 |
| lpErrno | INT* | エラーコードへのポインター。 |
公式ドキュメント
LPWSPCloseSocket 関数は、ソケットを閉じます。
戻り値
エラーが発生しない場合、LPWSPCloseSocket はゼロを返します。それ以外の場合は SOCKET_ERROR が返され、具体的なエラーコードは lpErrno で取得できます。
| エラーコード | 意味 |
|---|---|
| ネットワークサブシステムに障害が発生しました。 | |
| ブロッキング Windows Sockets 呼び出しが進行中であるか、サービスプロバイダーがコールバック関数をまだ処理しています。 | |
| ディスクリプターがソケットではありません。 | |
| ソケットが非ブロッキングとしてマークされており、SO_LINGER に 0 以外のタイムアウト値が設定されています。 |
解説(Remarks)
この関数は、ソケットを閉じます。より正確には、ソケットディスクリプター s を解放します。そのため、以降の s への参照はエラー WSAENOTSOCK で失敗します。これが基になるソケットへの最後の参照である場合、関連付けられた名前情報とキューに入れられたデータは破棄されます。そのソケットで保留中のブロッキング呼び出しまたは非同期呼び出し (このプロセス内のいずれかのスレッドが発行したもの) は、通知メッセージを送出することなくキャンセルされます。このプロセス内のいずれかのスレッドが発行した、保留中のオーバーラップ操作もキャンセルされます。これらのオーバーラップ操作に指定された完了アクション (イベント、完了ルーチン、完了ポートなど) は実行されます。この場合、保留中のオーバーラップ操作はエラー状態 WSA_OPERATION_ABORTED で失敗します。LPWSPCloseSocket の呼び出し後に FD_CLOSE が送出されることはありません。
LPWSPCloseSocket の動作は次のようにまとめられます。
SO_DONTLINGER が有効な場合 (既定の設定)、LPWSPCloseSocket は直ちに戻り、接続はバックグラウンドで正常に閉じられます。
SO_LINGER がタイムアウト 0 で有効な場合、LPWSPCloseSocket は直ちに戻り、接続はリセット/終了されます。
または
ブロッキングソケットで SO_LINGER が 0 以外のタイムアウトとともに有効な場合、LPWSPCloseSocket は、すべてのデータが送信されるかタイムアウトが経過するまでブロックします。
非ブロッキングソケットで SO_LINGER が 0 以外のタイムアウトとともに有効な場合、LPWSPCloseSocket は直ちに戻り、失敗を示します。
LPWSPCloseSocket のセマンティクスは、ソケットオプション SO_LINGER および SO_DONTLINGER によって次のように変わります。
| オプション | 間隔 | クローズの種類 | クローズを待機するか |
|---|---|---|---|
| SO_DONTLINGER | 任意 | 正常 (Graceful) | いいえ |
| SO_LINGER | 0 | 強制 (Hard) | いいえ |
| SO_LINGER | 0 以外 | 正常 (Graceful) | はい |
SO_LINGER が設定されていて (つまり linger 構造体の l_onoff メンバーが 0 以外で)、タイムアウト間隔 l_linger が 0 の場合、キューに入れられたデータがまだ送信または確認応答されていなくても、LPWSPCloseSocket はブロックされません。これは強制的なクローズ (ハードクローズ、abortive close) と呼ばれます。ソケットの仮想回線が直ちにリセットされ、未送信のデータはすべて失われるためです。回線のリモート側での LPWSPRecv の呼び出しは、WSAECONNRESET で失敗します。
ブロッキングソケットで SO_LINGER が 0 以外のタイムアウト間隔とともに設定されている場合、LPWSPCloseSocket の呼び出しは、残りのデータが送信されるかタイムアウトが経過するまでブロックします。これは正常な切断 (graceful disconnect) と呼ばれます。すべてのデータが送信される前にタイムアウトが経過した場合、サービスプロバイダーは LPWSPCloseSocket が戻る前に接続を終了する必要があります。
非ブロッキングソケットで 0 以外のタイムアウト間隔を指定して SO_LINGER を有効にすることは推奨されません。この場合、クローズ操作を直ちに完了できないと、LPWSPCloseSocket の呼び出しはエラー WSAEWOULDBLOCK で失敗します。LPWSPCloseSocket が WSAEWOULDBLOCK で失敗した場合、ソケットハンドルは引き続き有効であり、切断は開始されません。
Winsock SPI クライアントは、ソケットを閉じるために LPWSPCloseSocket を再度呼び出す必要がありますが、Winsock SPI クライアントが次のいずれかを行わない限り、LPWSPCloseSocket は失敗し続ける可能性があります。
- SO_DONTLINGER を無効にする。
- タイムアウト 0 で SO_LINGER を有効にする。
- LPWSPShutdown を呼び出してクローズを開始する。
ストリームソケットに SO_DONTLINGER が設定されている場合 (つまり linger 構造体の l_onoff メンバーが 0 の場合)、LPWSPCloseSocket の呼び出しは、ソケットがブロッキングか非ブロッキングかにかかわらず直ちに戻り、WSAEWOULDBLOCK にはなりません。ただし、送信のためにキューに入れられたデータは、基になるソケットが閉じられる前に、可能であれば送信されます。これは正常な切断と呼ばれ、既定の動作です。
この場合、Winsock プロバイダーは、正常な切断が完了するまで、またはプロバイダーが決定した時間内に操作を完了できずに接続を終了するまで、ソケットに関連付けられたリソースを保持できる点に注意してください。これは、利用可能なすべてのソケットを使用しようとする Winsock クライアントに影響する可能性があります。これが既定の動作であり、SO_DONTLINGER は既定で設定されています。
Microsoft 公式リファレンス: 英語 (en-us) · 日本語 (ja-jp) · 原文ソース (GitHub)