原 golang http server 探究(下)

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

在上一篇裡面我們通過:

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裡面的流通過程已經非常的清晰了是不是 ?

關注程式猿公眾帳號:

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.