在上一篇里面我们通过:
func main() { http.HandleFunc("/hello",func(w http.ResponseWriter,r *http.Request) { io.WriteString(w,"hello") }) http.ListenAndServe(":9010",nil) }
分析了 http.handleFunc 的路由调用之间的关系。这次。我们分析一下 http.ListenAndServe():
http.ListenAndServe(addr string,handler Handler)
函数的内部实现:
func ListenAndServe(addr string,handler Handler) error { server := &Server{Addr: addr,Handler: handler} return server.ListenAndServe() }
发现这个http.ListenAndServe 其实调用的是 Server.ListenAndServe。我们先来看看 Server的结构:
type Server struct { Addr string // TCP address to listen on,":http" if empty Handler Handler //处理器,如果为空则使用 http.DefaultServeMux ReadTimeout time.Duration WriteTimeout time.Duration .... }
看到这个Handler,再联系上次我们分析的http.HandleFunc。我们发现他们默认都使用了 http.DefaultServeMux 这个路由处理器。而在这个处理器里面 刚好保存了我们注册的一个路由。/hello。然后我们看看 server.ListenAndServe 是怎么监听和分发路由的。
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)}) }
在 server.ListenAndServe 里面注册了一个tcp的监听器,监听我们注册的网络端口。接着继续调用
server.Serve(l net.Listener) error
进行服务。
func (srv *Server) Serve(l net.Listener) error { ....... for { rw,e := l.Accept() .... c := srv.newConn(rw) c.setState(c.rwc,StateNew) // before Serve can return go c.serve(ctx) } }
开启一个for循环,接受net.accept()。接着使用了 srv.newConn(net.conn) 把一个tcp的conn转换成一个http.server#conn:
func (srv *Server) newConn(rwc net.Conn) *conn { c := &conn{ server: srv,rwc: rwc,} .... return c }
最后开启一个go协程对每个请求进行处理。
func (c *conn) serve(ctx context.Context) { // 客户端主机ip c.remoteAddr = c.rwc.RemoteAddr().String() .... // HTTP/1.x from here on. //读取请求的数据 c.r = &connReader{r: c.rwc} c.bufr = newBufioReader(c.r) c.bufw = newBufioWriterSize(checkConnErrorWriter{c},4<<10) ctx,cancelCtx := context.WithCancel(ctx) defer cancelCtx() for { w,err := c.readRequest(ctx) ...... serverHandler{c.server}.ServeHTTP(w,w.req) ... } }
请求经过七倒八倒,最后进入了:
serverHandler{c.server}.ServeHTTP(w,w.req)
并且调用了它里面的ServerHandler.serveHTTP。果断点开这个函数,豁然开朗,原来是调用了最上层:
http.DefaultServeMux.Handle
不信看这里:
type serverHandler struct { srv *Server } func (sh serverHandler) ServeHTTP(rw ResponseWriter,req *Request) { //sh.srv.Handler =server.handler handler := sh.srv.Handler if handler == nil { //我们最初传的参数就是 nil handler = DefaultServeMux } if req.RequestURI == "*" && req.Method == "OPTIONS" { handler = globalOptionsHandler{} } handler.ServeHTTP(rw,req) }
所以啊,最后的处理是函数是 路由里面的 ServeMux.ServeHTTP,昨晚我们已经分析了ServeMux.ServeHTTP执行的是 我们自己传进去的函数。 服务器 开启以后一个请求 进来,首先调用的是 Server.ServeHTTP(rw ResponseWriter,req *Request).
func (mux *ServeMux) ServeHTTP(w ResponseWriter,r *Request) { ..... h,_ := mux.Handler(r) h.ServeHTTP(w,r) }
上面的函数 再经过倒腾,最后转到这到ServeMux#handler函数里面:
func (mux *ServeMux) handler(host,path string) (h Handler,pattern string) { mux.mu.RLock() defer mux.mu.RUnlock() // Host-specific pattern takes precedence over generic ones if mux.hosts { h,pattern = mux.match(host + path) } if h == nil { h,pattern = mux.match(path) } if h == nil { h,pattern = NotFoundHandler(),"" } return }
在这个方法 里面就对 URL进行了匹配。匹配上就返回对应的URL的handle,否则就是 调用 NotFoundHandler。然后调用muxEntry.h,就是我们自定义处理的逻辑函数。
这样一个完整的 请求 http请求在golang里面的流通过程已经非常的清晰了是不是 ?
关注程序猿公众账号:
原文链接:https://www.f2er.com/go/189427.html