Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get address for http.ListenAndServe

Tags:

go

Say I start a server like so:

srv := http.Server{
    Addr:    ":0",
    Handler: http.FileServer(http.Dir(".")),
}
go srv.ListenAndServe()
log.Printf("Listening on ???")

How can I tell which port was picked? :0 is designed to pick a random ephemeral port by the OS, but I need to know which one was picked.

NOTE: 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.

like image 202
chowey Avatar asked Jul 26 '15 00:07

chowey


People also ask

What is HTTP ListenAndServe?

ListenAndServe function to start the server and tell it to listen for new HTTP requests and then serve them using the handler functions you set up.

What is default ServeMux?

ServerMux is a type which implements the Handler interface, all servers have one. In your first example the server just uses the default handler.

Does ListenAndServe block?

If we look at the ListenAndServe function, it has the following syntax. When we call http. ListenAndServer() with appropriate arguments, it starts an HTTP server and blocks the current goroutine. If we run this function inside the main function, it will block the main goroutine (started by the main function).


2 Answers

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).

like image 128
Stephen Weinberg Avatar answered Sep 28 '22 11:09

Stephen Weinberg


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

like image 31
Massimo Zerbini Avatar answered Sep 28 '22 12:09

Massimo Zerbini