Does http.DefaultTransport use keep-alive connections?

1,723 views
Skip to first unread message

Aaron Jacobs

unread,
Oct 21, 2012, 5:24:42 PM10/21/12
to golan...@googlegroups.com
I'm having some reading comprehension difficulties with the `http` package
documentation; I'm hoping somebody can help.

The docs for type Transport say that it "can [...] cache connections for
future re-use". The zero-type for the struct appears to support this, with
DisableKeepAlives false and MaxIdleConnsPerHost = 0 documented to use
DefaultMaxIdleConnsPerHost, which is 2.

Then DefaultTransport is defined like this:

var DefaultTransport RoundTripper = &Transport{Proxy: ProxyFromEnvironment}

If I'm reading the Transport docs correctly, then this should support
keep-alive and cache up to 2 idle connections. However, the docs for
DefaultTransport say this:

> DefaultTransport is the default implementation of Transport and is
> used by DefaultClient. It establishes a new network connection for
> each call to Do [...].

So does it use keep-alive connections? In reality it appears not to (just
based on clear ramp-up times for large uploads viewed with the Network tab in
OS X's Activity Monitor), but I'm not positive. If not, what is the correct
and efficient way to do many repeated requests to a single server?

Thanks,
Aaron

Russ Cox

unread,
Oct 21, 2012, 5:53:28 PM10/21/12
to Aaron Jacobs, golan...@googlegroups.com
The program below works for me (only dials once). Almost always,
failure to reuse a connection turns out to be forgetting to call
r.Body.Close.

package main

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

func dial(netw, addr string) (net.Conn, error) {
fmt.Printf("dial %s %s\n", netw, addr)
return net.Dial(netw, addr)
}

func main() {
http.DefaultTransport.(*http.Transport).Dial = dial
for i := 0; i < 10; i++ {
r, err := http.Get("http://www.google.com/robots.txt")
if err != nil {
log.Fatal(err)
}
r.Body.Close()
}
}

Aaron Jacobs

unread,
Oct 21, 2012, 6:11:37 PM10/21/12
to Russ Cox, golan...@googlegroups.com
On Mon, Oct 22, 2012 at 8:53 AM, Russ Cox <r...@golang.org> wrote:
> The program below works for me (only dials once). Almost always,
> failure to reuse a connection turns out to be forgetting to call
> r.Body.Close.

Yep, happens for me too. I also modified your program to use Do instead of
Get, and the same thing happens. But the docs say this:

> DefaultTransport is the default implementation of Transport and is
> used by DefaultClient. It establishes a new network connection for
> each call to Do [...].

It seems they're incorrect then, right?

Aaron

Shivakumar GN

unread,
Aug 8, 2013, 10:22:54 PM8/8/13
to golang-nuts
Below behavior no longer seems to be true. Current tip seems to dial each time (tried same code below).
How to get back same behavior?

Brad Fitzpatrick

unread,
Aug 9, 2013, 12:31:06 PM8/9/13
to Aaron Jacobs, golang-nuts
Docs at tip no longer have that wording.  It now says:

// DefaultTransport is the default implementation of Transport and is
// used by DefaultClient. It establishes network connections as needed
// and caches them for reuse by subsequent calls.
....

Also, you have to read the entire res.Body for it to re-use the connection.  The old "try to read until the end on Close" behavior was too problematic and surprising.  If you want that behavior, it's easily enough to implement in your own code with a ReadCloser wrapper.





--



Reply all
Reply to author
Forward
0 new messages