[インデックス 19349] ファイルの概要
このコミットは、Go言語の標準ライブラリnet
パッケージにおけるTCPConn.SetLinger
メソッドのドキュメントを修正するものです。具体的には、sec > 0
の場合の挙動に関する説明が、より正確かつ詳細になるように変更されています。この変更は、SO_LINGER
ソケットオプションの動作をより適切に反映させることを目的としています。
コミット
commit d145f0f0f8b735b7cde299e169937b2827832202
Author: Mikio Hara <mikioh.mikioh@gmail.com>
Date: Wed May 14 12:12:01 2014 +0900
net: fix documentation for SetLinger
Fixes #7974.
LGTM=iant
R=golang-codereviews, iant
CC=golang-codereviews
https://golang.org/cl/95320043
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/d145f0f0f8b735b7cde299e169937b2827832202
元コミット内容
このコミットは、src/pkg/net/tcpsock_plan9.go
とsrc/pkg/net/tcpsock_posix.go
の2つのファイルのドキュメントコメントを修正しています。変更の要点は、SetLinger
メソッドのsec
引数が正の値(sec > 0
)の場合の挙動に関する説明の修正です。
変更前は、sec > 0
の場合に「Closeはデータを送信し、確認応答されるのを最大sec秒間ブロックする」と記述されていました。
変更後は、「sec < 0
の場合と同様に、データはバックグラウンドで送信される。一部のオペレーティングシステムでは、sec秒経過後に残りの未送信データが破棄される場合がある」と修正されています。
変更の背景
このコミットの背景には、net.SetLinger
メソッドのドキュメントが、実際のSO_LINGER
ソケットオプションの挙動と完全に一致していなかったという問題があります。特に、sec > 0
の場合の挙動に関する説明が誤解を招く可能性がありました。
TCPソケットのSO_LINGER
オプションは、ソケットがクローズされる際の未送信データの扱いを制御します。
sec < 0
(デフォルト):Close()
は即座に返り、OSがバックグラウンドでデータの送信を完了させます。sec == 0
:Close()
は即座に返り、OSは未送信データを破棄し、接続を強制的にリセット(RSTパケットを送信)します。これは「ハードクローズ」または「アボーティブクローズ」と呼ばれます。sec > 0
:Close()
は、指定された秒数(sec
)の間、未送信データの送信と確認応答を待ちます。しかし、一部のOSでは、このタイムアウトが経過すると、残りの未送信データが破棄される可能性があります。また、Go言語の内部的な非ブロッキングI/Oの性質上、Close()
が常にブロックするとは限りません。
元のドキュメントでは、sec > 0
の場合に「Closeがブロックする」という点が強調されていましたが、これはOSの実装やGoの非ブロッキングI/Oの特性によっては常に真ではないため、より正確な記述が求められました。この修正は、ユーザーがSetLinger
の挙動を正しく理解し、予期せぬデータ損失や接続終了の挙動を避けるために重要です。
コミットメッセージにあるFixes #7974
は、このドキュメントの不正確さを指摘するIssueが存在したことを示唆しています。
前提知識の解説
TCPソケットとclose()
の挙動
TCP(Transmission Control Protocol)は、信頼性の高いコネクション指向のプロトコルです。アプリケーションがTCPソケットをクローズする際、単にソケットを閉じるだけでなく、未送信データの扱いや接続の終了プロセスを考慮する必要があります。
通常、close()
が呼び出されると、OSはソケットの送信バッファに残っているデータをバックグラウンドで送信しようとします。この際、close()
は即座に返り、アプリケーションはデータの送信が完了したかどうかを知ることはできません。
SO_LINGER
ソケットオプション
SO_LINGER
は、TCPソケットのclose()
関数の挙動を制御するためのソケットオプションです。setsockopt()
システムコールを通じて設定され、linger
構造体(l_onoff
とl_linger
の2つのメンバを持つ)を使用します。
l_onoff
:SO_LINGER
オプションを有効にするか(非ゼロ)、無効にするか(ゼロ)を決定します。l_linger
: リンガータイム(秒単位)を表す整数です。
SO_LINGER
の主な挙動は以下の3つです。
-
SO_LINGER
無効(デフォルト):l_onoff = 0
close()
は即座に返ります。- OSは残りのデータをバックグラウンドで送信しようとします。
- ソケットはグレースフルシャットダウン(FIN-ACKシーケンス)を行います。
-
SO_LINGER
有効、l_linger = 0
(アボーティブクローズ):l_onoff = 非ゼロ
,l_linger = 0
close()
は即座に返ります。- 送信バッファ内の未送信データはすべて破棄されます。
- OSはピアにRST(リセット)パケットを送信し、接続を即座に強制終了します。
- データ損失のリスクがあるため、通常は推奨されません。
-
SO_LINGER
有効、l_linger > 0
(タイムアウト付きグレースフルクローズ):l_onoff = 非ゼロ
,l_linger = 非ゼロ
close()
は、未送信データがすべて送信され確認応答されるか、または指定されたl_linger
タイムアウトが経過するまでブロックします(ブロッキングソケットの場合)。- タイムアウトが経過してもデータがすべて送信されなかった場合、接続は強制的にクローズされ、残りのデータは破棄される可能性があります。
- このオプションは、すべての保留中のデータが接続が完全にクローズされる前に送信されることを保証し、より信頼性の高いシャットダウンを提供します。
Go言語のnet
パッケージ
Go言語のnet
パッケージは、ネットワークI/Oのプリミティブを提供します。net.TCPConn
はTCPネットワーク接続を表し、SetLinger
メソッドはこの接続のSO_LINGER
オプションを設定するために使用されます。Goは内部的に非ブロッキングI/Oを使用しているため、SetLinger(sec > 0)
を設定しても、Close()
が常にブロックするとは限らないという点が重要です。
技術的詳細
このコミットの技術的な核心は、SetLinger
メソッドのドキュメントが、SO_LINGER
ソケットオプションのl_linger > 0
の挙動をより正確に反映するように修正された点にあります。
元のドキュメントでは、sec > 0
の場合にClose()
が「最大sec秒間ブロックする」と明記されていましたが、これは常に真ではありません。
- OSによる挙動の違い:
SO_LINGER
の挙動は、オペレーティングシステムによって微妙に異なる場合があります。特に、タイムアウトが経過した後の未送信データの扱いは、OSによって「破棄される可能性がある」という不確実性が存在します。元のドキュメントでは、この「破棄される可能性」が明示されていませんでした。 - Goの非ブロッキングI/O: Go言語の
net
パッケージは、内部的に非ブロッキングI/Oを使用しています。これにより、SetLinger(sec > 0)
を設定しても、Close()
が必ずしも指定された秒数だけブロックするとは限りません。例えば、データがすぐに送信されるか、OSがすぐに接続をクローズする決定を下す場合、Close()
は即座に返る可能性があります。元のドキュメントの記述は、このGoの内部実装の側面を考慮していませんでした。
修正後のドキュメントは、これらの点を踏まえ、sec > 0
の場合の挙動を以下のように記述しています。
If sec > 0, the data is sent in the background as with sec < 0. On some operating systems after sec seconds have elapsed any remaining unsent data may be discarded.
これは、sec < 0
の場合と同様にデータがバックグラウンドで送信されることを明確にしつつ、タイムアウト後にデータが破棄される可能性を明示することで、より現実的で正確な情報を提供しています。これにより、開発者はSetLinger(sec > 0)
を使用する際に、データ損失のリスクをより正確に評価できるようになります。
この変更は、機能的なバグ修正ではなく、ドキュメントの正確性を向上させるためのものです。しかし、ネットワークプログラミングにおいてソケットのクローズ挙動は非常に重要であり、誤解を招くドキュメントはアプリケーションの信頼性に影響を与える可能性があるため、この修正は非常に価値があります。
コアとなるコードの変更箇所
このコミットは、Goのnet
パッケージ内のTCPソケット実装に関連する2つのファイルのドキュメントコメントを変更しています。
src/pkg/net/tcpsock_plan9.go
--- a/src/pkg/net/tcpsock_plan9.go
+++ b/src/pkg/net/tcpsock_plan9.go
@@ -44,17 +44,18 @@ func (c *TCPConn) CloseWrite() error {
return c.fd.closeWrite()
}
-// SetLinger sets the behavior of Close() on a connection which still
+// SetLinger sets the behavior of Close on a connection which still
// has data waiting to be sent or to be acknowledged.
//
-// If sec < 0 (the default), Close returns immediately and the
-// operating system finishes sending the data in the background.
+// If sec < 0 (the default), the operating system finishes sending the
+// data in the background.
//
-// If sec == 0, Close returns immediately and the operating system
-// discards any unsent or unacknowledged data.
+// If sec == 0, the operating system discards any unsent or
+// unacknowledged data.
//
-// If sec > 0, Close blocks for at most sec seconds waiting for data
-// to be sent and acknowledged.
+// If sec > 0, the data is sent in the background as with sec < 0. On
+// some operating systems after sec seconds have elapsed any remaining
+// unsent data may be discarded.
func (c *TCPConn) SetLinger(sec int) error {
return syscall.EPLAN9
}
src/pkg/net/tcpsock_posix.go
--- a/src/pkg/net/tcpsock_posix.go
+++ b/src/pkg/net/tcpsock_posix.go
@@ -90,17 +90,18 @@ func (c *TCPConn) CloseWrite() error {
return c.fd.closeWrite()
}
-// SetLinger sets the behavior of Close() on a connection which still
+// SetLinger sets the behavior of Close on a connection which still
// has data waiting to be sent or to be acknowledged.
//
-// If sec < 0 (the default), Close returns immediately and the
-// operating system finishes sending the data in the background.
+// If sec < 0 (the default), the operating system finishes sending the
+// data in the background.
//
-// If sec == 0, Close returns immediately and the operating system
-// discards any unsent or unacknowledged data.
+// If sec == 0, the operating system discards any unsent or
+// unacknowledged data.
//
-// If sec > 0, Close blocks for at most sec seconds waiting for data
-// to be sent and acknowledged.
+// If sec > 0, the data is sent in the background as with sec < 0. On
+// some operating systems after sec seconds have elapsed any remaining
+// unsent data may be discarded.
func (c *TCPConn) SetLinger(sec int) error {
if !c.ok() {
return syscall.EINVAL
コアとなるコードの解説
変更は、SetLinger
関数のドキュメントコメントに限定されています。
-
SetLinger sets the behavior of Close() on a connection which still
からSetLinger sets the behavior of Close on a connection which still
:Close()
の括弧が削除され、より自然な英語表現になっています。これは軽微な修正ですが、ドキュメントの品質向上に貢献します。
-
If sec < 0 (the default), Close returns immediately and the operating system finishes sending the data in the background.
からIf sec < 0 (the default), the operating system finishes sending the data in the background.
:Close returns immediately and
の部分が削除されました。sec < 0
の場合、Close
が即座に返ることは暗黙の了解であり、OSがバックグラウンドでデータを送信するという主要な挙動に焦点を当てることで、より簡潔で分かりやすい記述になっています。
-
If sec == 0, Close returns immediately and the operating system discards any unsent or unacknowledged data.
からIf sec == 0, the operating system discards any unsent or unacknowledged data.
:- 同様に、
Close returns immediately and
の部分が削除されました。sec == 0
の場合もClose
は即座に返るため、主要な挙動である「未送信データの破棄」に焦点を当てています。
- 同様に、
-
If sec > 0, Close blocks for at most sec seconds waiting for data to be sent and acknowledged.
からIf sec > 0, the data is sent in the background as with sec < 0. On some operating systems after sec seconds have elapsed any remaining unsent data may be discarded.
:- これが最も重要な変更点です。
- 変更前は「Closeが最大sec秒間ブロックする」と記述されていましたが、これは常に真ではありません。
- 変更後は、「
sec < 0
の場合と同様に、データはバックグラウンドで送信される」と、非ブロッキングI/Oの特性を考慮した記述になっています。 - さらに、「一部のオペレーティングシステムでは、sec秒経過後に残りの未送信データが破棄される場合がある」という重要な注意書きが追加されました。これにより、
SO_LINGER
のOS依存性や、タイムアウト後のデータ損失の可能性が明確に示され、ドキュメントの正確性が大幅に向上しています。
これらの変更は、Goのnet
パッケージのドキュメントの品質を高め、開発者がSetLinger
メソッドの挙動をより正確に理解し、適切なネットワークアプリケーションを構築するのに役立ちます。
関連リンク
- Go言語
net
パッケージのドキュメント: https://pkg.go.dev/net net.TCPConn.SetLinger
のドキュメント (最新版): https://pkg.go.dev/net#TCPConn.SetLinger- TCP
SO_LINGER
オプションに関する一般的な情報源 (例: Linux man pages, POSIX Sockets API ドキュメントなど)
参考にした情報源リンク
- Go言語の
net.SetLinger
に関するWeb検索結果 - TCP
SO_LINGER
オプションに関するWeb検索結果 - Go言語のIssueトラッカー (Issue #7974は直接見つからなかったが、コミットメッセージから存在が示唆される)
- TCP/IPプロトコルに関する一般的な知識