web-dev-qa-db-ja.com

応答が8kbを超えると、golang httpサーバーが「壊れたパイプ」で失敗するのはなぜですか?

以下にWebサーバーの例を示します。ここで、curl localhost:3000 -vを呼び出してから^C(キャンセル)すると、すぐに(1秒前に)write tcp 127.0.0.1:3000->127.0.0.1:XXXXX: write: broken pipeが報告されます。

package main

import (
    "fmt"
    "net/http"
    "time"
)

func main() {
    log.Fatal(http.ListenAndServe(":3000", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            time.Sleep(1 * time.Second)

            // Why 8061 bytes? Because the response header on my computer
            // is 132 bytes, adding up the entire response to 8193 (1 byte 
            // over 8kb)
            if _, err := w.Write(make([]byte, 8061)); err != nil {
                    fmt.Println(err)
                    return
            }   
    })))
}

私のデバッグに基づいて、これは応答全体が8192バイト(または8kb)を超えて書き込んでいる場合にのみ発生すると結論付けることができました。応答全体の書き込みが8192未満の場合、broken pipeエラーは返されません。

私の質問はこの8192バイト(または8kb)のバッファ制限はどこに設定されていますか?これはGolangのHTTP書き込みバッファの制限ですか?これは、チャンク化されている応答に関連していますか?これはcurlクライアントまたはブラウザクライアントにのみ関連していますか?この制限を変更して、接続が閉じられる前に(デバッグ目的で)より大きなバッファーを書き込むことができるようにするにはどうすればよいですか?

ありがとう!

10
eldosoa

net/http/server.goでは、出力バッファは4<<10、つまり4KBに設定されます。

8KBでエラーが表示される理由は、閉じたリモート接続を検出するためにソケットへの書き込みが少なくとも2回必要なためです。最初の書き込みは成功しますが、リモートホストはRSTパケットを送信します。 2回目の書き込みは、閉じたソケットへの書き込みであり、これがbroken pipeエラーを返します。

ソケット書き込みバッファと接続待ち時間によっては、最初のRSTパケットが登録される前にさらに多くの書き込みが成功する可能性があります。

14
JimB