Go源碼分析——http.ListenAndServe()是如何工作的

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

Go對web伺服器的編寫提供了非常好的支援,標準庫中提供了net/http包來方便編寫伺服器。許多教程和書籍在講到用Go編寫web伺服器時都會直接教新手用http包寫一個最簡單的hello world伺服器,例子差不多都會像這樣:

// 這就是用Go實現的一個最簡短的hello world伺服器.package mainimport "net/http"func main() {http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {w.Write([]byte(`hello world`))})http.ListenAndServe(":3000", nil) // <-今天講的就是這個ListenAndServe是如何工作的}

可以看到,代碼真的非常簡短,只需要幾行,我們今天要分析的是http.ListenAndServe(),看看這裡面到底都做了些什麼。


首先,http.ListenAndServe用到的所有依賴都在Go源碼中的/src/pkg/net/http/server.go檔案中,開啟它會發現這頁代碼非常長,有2000+行,我們Ctrl+F直接找我們感興趣的部分,發現在1770行左右的部分找到了http.ListenAndServe的定義:

func ListenAndServe(addr string, handler Handler) error {// 建立一個Server結構體,調用該結構體的ListenAndServer方法然後返回server := &Server{Addr: addr, Handler: handler}return server.ListenAndServe()}
從這個函數中就可以看出,調用http.ListenAndServe之後真正起作用的是Server結構體LisntenAndServe方法,給http.ListenAndServe傳遞的參數只是用來建立一個Server結構體執行個體,Server結構體的定義如下:

type Server struct {Addr           string        // 伺服器的IP地址和連接埠資訊Handler        Handler       // 請求處理函數的路由複用器ReadTimeout    time.Duration WriteTimeout   time.DurationMaxHeaderBytes int       TLSConfig      *tls.Config  TLSNextProto map[string]func(*Server, *tls.Conn, Handler)ConnState func(net.Conn, ConnState)ErrorLog *log.LoggerdisableKeepAlives int32 }
如果我們不傳具體的參數給http.ListenAndServe,那麼它會自動以":http"(等價於":80")和DefaulServeMux作為參數來建立Server結構體執行個體。

接下來繼續看看Server.ListenAndServe裡面都做了些什麼,1675行左右可以找到定義:

func (srv *Server) ListenAndServe() error {addr := srv.Addrif addr == "" {addr = ":http"  // 如果不指定伺服器位址資訊,預設以":http"作為地址資訊}ln, err := net.Listen("tcp", addr)    // 這裡建立了一個TCP Listener,之後用於接收用戶端的串連請求if err != nil {return err}return srv.Serve(tcpKeepAliveListener{ln.(*net.TCPListener)})  // 調用Server.Serve()函數並返回}
可以看到,Server.ListenAndServe中建立了一個伺服器Listener,然後在返回時把它傳給了Server.Serve()方法並調用Server.Serve()。


繼續分析Server.Serve,定義的位置在1690行左右:

func (srv *Server) Serve(l net.Listener) error {defer l.Close()var tempDelay time.Duration // 這個迴圈就是伺服器的主迴圈了,通過傳進來的listener接收來自用戶端的請求並建立串連,// 然後為每一個串連建立routine執行c.serve(),這個c.serve就是具體的服務處理了for {rw, e := l.Accept()if e != nil {if ne, ok := e.(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", e, tempDelay)time.Sleep(tempDelay)continue}return e}tempDelay = 0c, err := srv.newConn(rw)if err != nil {continue}c.setState(c.rwc, StateNew) // before Serve can returngo c.serve() // <-這裡為每一個建立的串連建立routine之後進行服務}}

我們可以接著看看這個conn.serve()裡面是怎麼進行服務的,代碼在1090行附近,只看其中的主要部分:

func (c *conn) serve() {origConn := c.rwc // copy it before it's set nil on Close or Hijack// 這裡做了一些延遲釋放和TLS相關的處理...// 前面的部分都可以忽略,這裡才是主要的迴圈for {w, err := c.readRequest()  // 讀取用戶端的請求// ...serverHandler{c.server}.ServeHTTP(w, w.req) //這裡對請求進行處理if c.hijacked() {return}w.finishRequest()if w.closeAfterReply {if w.requestBodyLimitHit {c.closeWriteAndWait()}break}c.setState(c.rwc, StateIdle)}}


經過一路的分析,http.ListenAndServe工作的流程就差不多明晰了,我們可以總結成一張流程圖:





如果轉載請註明出處:http://blog.csdn.net/gophers


相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.