How to get address for http.ListenAndServe

I would prefer not to create my own listener and use srv.Listen(ln), since srv.ListenAndServe() has a good default (but unexported) listener that I want to use.

Why not? ListenAndServe() is extremely simple to implement yourself. You can read the source code for it yourself:

func (srv *Server) ListenAndServe() error {
    addr := srv.Addr
    if addr == "" {
        addr = ":http"
    }
    ln, err := net.Listen("tcp", addr)
    if err != nil {
        return err
    }
    return srv.Serve(tcpKeepAliveListener{ln.(*net.TCPListener)})
}

The answer is that you will need to use write your own ListenAndServe() that gives you the information you want. It is much easier than you believe however. The entire thing isn't more than 20 lines (assuming you want to set keep-alives with tcpKeepAliveListener).


As of Go 1.14.1, net/http no longer wraps the TCP listener!

Looking at the source code, it is now:

func (srv *Server) ListenAndServe() error {
    if srv.shuttingDown() {
        return ErrServerClosed
    }
    addr := srv.Addr
    if addr == "" {
        addr = ":http"
    }
    ln, err := net.Listen("tcp", addr)
    if err != nil {
        return err
    }
    return srv.Serve(ln)
}

This is due to this commit, where the "keepalive" part of the listener was moved to the standard net package and is now turned on by default.

So, don't worry about it! Just create your own listener.


Example

ln, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
    return err
}
go srv.Serve(ln)
log.Printf("Listening on %s", ln.Addr().String())

You can select a free port before configuring the server address. The simpler way to get a free port is to create a listener, so you can obtain the same result following Stephen suggestion.

func GetFreePort() (int, error) {
    ln, err := net.Listen("tcp", ":0")
    if err != nil {
        return 0, err
    }
    err = ln.Close()
    if err != nil {
        return 0, err
    }
    return ln.Addr().(*net.TCPAddr).Port, nil
}

Here a complete example https://play.golang.org/p/bG4OpmQbz9s

Tags:

Go