http.ListenAndServe
func ListenAndServe(addr string, handler Handler) error
ListenAndServe监听TCP地址addr,并且会使用handler参数调用Serve函数处理接收到的连接。handler参数一般会设为nil,此时会使用DefaultServeMux。

接下来我们看一下这个函数的主要源码流程。
一、通过ListenAndServe的参数创建Server结构体
func ListenAndServe(addr string, handler Handler) error { server := &Server{Addr: addr, Handler: handler} return server.ListenAndServe() }
Server 定义运行HTTP服务器的参数。Server的零值是一个有效的配置。

第一层相当于封装了一下创建Server结构体的过程,更易于用户使用,创建Server结构体之后,调用Server结构体的ListenAndServe方法。
二、定义监听信息(Listen)调用Serve处理请求
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) }
ListenAndServe监听TCP网络地址 srv.Addr,然后调用服务来处理传入连接的请求。
第二层首先根据srv中Addr定义了监听信息ln, err := net.Listen("tcp", addr),然后把监听对象ln作为srv(Server)对象调用Serve方法的参数。
三、监听器持续监听并Accept请求创建连接,处理连接
func (srv *Server) Serve(l net.Listener) error { ...... for { rw, err := l.Accept() //接收 if err != nil { if srv.shuttingDown() { return ErrServerClosed } if ne, ok := err.(net.Error); ok && ne.Temporary() { if tempDelay == 0 { tempDelay = 5 * time.Millisecond } else { tempDelay *= 2 } if max := 1 * time.Second; tempDelay > max { tempDelay = max } srv.logf("http: Accept error: %v; retrying in %v", err, tempDelay) time.Sleep(tempDelay) continue } return err } connCtx := ctx if cc := srv.ConnContext; cc != nil { connCtx = cc(connCtx, rw) if connCtx == nil { panic("ConnContext returned nil") } } tempDelay = 0 c := srv.newConn(rw) //创建新连接 c.setState(c.rwc, StateNew, runHooks) // before Serve can return go c.serve(connCtx) //开启单独协程处理连接 } }
服务接收监听器上的传入连接,创建一个新的服务协程为每个连接。
Serve方法开启一个for循环,for循环中不断从监听器中接受每一个请求Accept,然后根据获取到的请求创建新的连接,最后开启一个新的协程服务go c.serve(connCtx)单独处理这个连接。
四、serve服务处理这个连接
func (c *conn) serve(ctx context.Context) { ...... serverHandler{c.server}.ServeHTTP(w, w.req) ...... }
第四层主要流程serve函数中会判断是否为https连接,如果是就升级为https连接。接着创建读写文本,最后通过serverHandler结构体调用相应的ServeHTTP方法处理。
五、ServeHttp具体处理逻辑
func (sh serverHandler) ServeHTTP(rw ResponseWriter, req *Request) { handler := sh.srv.Handler if handler == nil { handler = DefaultServeMux } if !sh.srv.DisableGeneralOptionsHandler && req.RequestURI == "*" && req.Method == "OPTIONS" { handler = globalOptionsHandler{} } handler.ServeHTTP(rw, req) }
第五层主要流程是如果server结构中自带了相应的Handler对象的话,就调用handler自己实现的ServeHTTP函数,如果没有自带的话,就使用标准库中默认DefaultServeMux作为handler。
六、DefaultServeMux默认处理逻辑
//部分源码 type ServeMux struct { mu sync.RWMutex m map[string]muxEntry es []muxEntry hosts bool } type muxEntry struct { h Handler pattern string } var DefaultServeMux = &defaultServeMux var defaultServeMux ServeMux ...... func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) { if r.RequestURI == "*" { if r.ProtoAtLeast(1, 1) { w.Header().Set("Connection", "close") } w.WriteHeader(StatusBadRequest) return } h, _ := mux.Handler(r) h.ServeHTTP(w, r) }
可以看到DefaultServeMux就是ServeMux数据结构的实例对象,标准库中路由注册的默认数据结构是map,key是接口的字符串,value是处理器。
第六层的主要流程处理逻辑为先使用request为参数,通过调用ServeMux中Handler方法查询ServeMux对象中的map,得到相应的handler,handler调用ServeHTTP函数处理。
type Handler interface { ServeHTTP(ResponseWriter, *Request) }
-
如果用户自定义实现了Handler,那么根据相应路径在map中查询到相对应的Handler,然后再调用用户自定义的ServeHTTP处理请求。
-
如果用户没有自定义Handler,只注册了对应处理函数(使用了http.HandleFunc),那么就会根据默认DefaultServeMux去map查询到这个函数类型Handler,然后再调用ServeHTTP处理函数。下面就是对应部分源码,可以看到,调用的ServeHTTP中又回调了用户自定义的函数。
type HandlerFunc func(ResponseWriter, *Request) // ServeHTTP calls f(w, r). func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) { f(w, r) }
总结
以上就是当调用接口时候ListenAndServe的大致流程。而其实不管是Golang本身标准库或者是市面上许多go-web框架也好,都是先把对应接口请求和处理加入到某个数据结构中,然后监听请求,被调用时,再去这个数据结构中查询再进行处理。