golang http server 探究(下)
在上一篇里面我们通过: 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里面的流通过程已经非常的清晰了是不是 ? 关注程序猿公众账号: (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |