golang http server 探究(下)

前端之家收集整理的这篇文章主要介绍了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里面的流通过程已经非常的清晰了是不是 ?

关注程序猿公众账号:

猜你在找的Go相关文章