Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"localhost: no such host" after 250 connections in Go when using ResponseWriter.Write

Tags:

networking

go

I have the following http client/server code:

Server

func main() {

    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        fmt.Println("Req: ", r.URL)
        w.Write([]byte("OK")) // <== PROBLEMATIC LINE
        // w.WriteHeader(200) // Works as expected
    })

    log.Fatal(http.ListenAndServe(":5008", nil))
}

Client

func main() {

    client := &http.Client{}

    for i := 0; i < 500; i++ {
        url := fmt.Sprintf("http://localhost:5008/%02d", i)
        req, _ := http.NewRequest("GET", url, nil)
        _, err := client.Do(req)

        if err != nil {
            fmt.Println("error: ", err)
        } else {
            fmt.Println("success: ", i)
        }

        time.Sleep(10 * time.Millisecond)
    }
}

When I run the client above against the server, then after 250 connections I get the following error from client.Do:
error: Get http://localhost:5008/250: dial tcp: lookup localhost: no such host and no more connections will succeed.

If I change the line in server from w.Write([]byte("OK")) ==> w.WriteHeader(200) however then there is no limit to the amount of connections and it works as expected.

What am I missing here?

like image 471
LK__ Avatar asked Nov 30 '22 01:11

LK__


1 Answers

You are not closing the body. When you do any writes from the server, the connection is left open because the response has not been read yet. When you just WriteHeader, the response is done and the connection can be reused or closed.

To be completely honest, I do not know why leaving open connections causes domain lookups to fail. Based on the fact that 250 is awfully close to the round number 256, I would guess there is an artificial limitation placed by the OS that you are hitting. Perhaps the max FDs allowed is 256? Seem low, but it would explain the problem.

func main() {
    client := &http.Client{}

    for i := 0; i < 500; i++ {
        url := fmt.Sprintf("http://localhost:5008/%02d", i)
        req, _ := http.NewRequest("GET", url, nil)
        resp, err := client.Do(req)

        if err != nil {
            fmt.Println("error: ", err)
        } else {
            fmt.Println("success: ", i)
        }
        resp.Body.Close()

        time.Sleep(10 * time.Millisecond)
    }
}
like image 69
Stephen Weinberg Avatar answered Dec 04 '22 15:12

Stephen Weinberg