Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 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.gosrc/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_onoffl_lingerの2つのメンバを持つ)を使用します。

  • l_onoff: SO_LINGERオプションを有効にするか(非ゼロ)、無効にするか(ゼロ)を決定します。
  • l_linger: リンガータイム(秒単位)を表す整数です。

SO_LINGERの主な挙動は以下の3つです。

  1. SO_LINGER無効(デフォルト):

    • l_onoff = 0
    • close()は即座に返ります。
    • OSは残りのデータをバックグラウンドで送信しようとします。
    • ソケットはグレースフルシャットダウン(FIN-ACKシーケンス)を行います。
  2. SO_LINGER有効、l_linger = 0(アボーティブクローズ):

    • l_onoff = 非ゼロ, l_linger = 0
    • close()は即座に返ります。
    • 送信バッファ内の未送信データはすべて破棄されます。
    • OSはピアにRST(リセット)パケットを送信し、接続を即座に強制終了します。
    • データ損失のリスクがあるため、通常は推奨されません。
  3. 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秒間ブロックする」と明記されていましたが、これは常に真ではありません。

  1. OSによる挙動の違い: SO_LINGERの挙動は、オペレーティングシステムによって微妙に異なる場合があります。特に、タイムアウトが経過した後の未送信データの扱いは、OSによって「破棄される可能性がある」という不確実性が存在します。元のドキュメントでは、この「破棄される可能性」が明示されていませんでした。
  2. 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.SetLingerに関するWeb検索結果
  • TCP SO_LINGERオプションに関するWeb検索結果
  • Go言語のIssueトラッカー (Issue #7974は直接見つからなかったが、コミットメッセージから存在が示唆される)
  • TCP/IPプロトコルに関する一般的な知識