net/http 分析

2020-08-11 22:23:58

net/http 原始碼分析

socket互動過程:
在这里插入图片描述
)

golang建立http伺服器的差不多兩步:

  • 註冊路由,提供url和handle函數的對映

    //範例
    http.HandleFunc("/", indexHeander)
    http.HandleFunc("/index", indexHandle)
    
  • 範例化server,監聽埠,建立連線

    log.Fatal(http.ListenAndServe(":8999", nil))
    

先講講用來註冊路由的HandleFunc函數.

HandleFunc函數結構簡單:使用預設的多路複用器註冊路由

可以看到,DefaultServeMux就是一個ServeMux的範例

//DefaultServeMux宣告如下
var DefaultServeMux = &defaultServeMux
 
var defaultServeMux ServeMux

type ServeMux struct {
   mu    sync.RWMutex//讀寫鎖
   m     map[string]muxEntry
   es    []muxEntry // slice of entries sorted from longest to shortest.
   hosts bool       // whether any patterns contain hostnames
}
...
func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
   DefaultServeMux.HandleFunc(pattern, handler)
}

在此前提下,可以發現HandleFunc實際呼叫的是DefaultServeMux的Handle()函數

func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
   ...省略部分判斷邏輯
   mux.Handle(pattern, HandlerFunc(handler))
}

ServeMux.Handle主要函數如下(省略部分異常)

(MuxEntry結構如下)

type muxEntry struct {
	h       Handler //處理常式
	pattern string  //URL
}
....
func (mux *ServeMux) Handle(pattern string, handler Handler) {
   mux.mu.Lock()
   defer mux.mu.Unlock()
   ...判斷邏輯
   if mux.m == nil {
      mux.m = make(map[string]muxEntry)
   }
   e := muxEntry{h: handler, pattern: pattern}
   //使用URL進行Hash對映
   mux.m[pattern] = e
   if pattern[len(pattern)-1] == '/' {
       //使用二分查詢將e插入到mux.es中(按照URL長度)
      mux.es = appendSorted(mux.es, e)
   }

   if pattern[0] != '/' {
      mux.hosts = true
   }
    //註冊路由完畢,開始返回
}

接下來是 http.ListenAndServe函數

//ListenAndServer函數用來監聽Tcp網路地址並且接下來會呼叫該地址
//使用處理程式來處理傳入上傳連線的請求
//被接收的連線會被設定爲TCP保持有效
//當使用預設的DefaultServerMux時,處理常式預設爲空
// ListenAndServe always returns a non-nil error.
func ListenAndServe(addr string, handler Handler) error {
   server := &Server{Addr: addr, Handler: handler}
   return server.ListenAndServe()
}
// ListenAndServe listens on the TCP network address srv.Addr and then
// calls Serve to handle requests on incoming connections.
// Accepted connections are configured to enable TCP keep-alives.
//
// ListenAndServe always returns a non-nil error. After Shutdown or Close,
// the returned error is ErrServerClosed.
func (srv *Server) ListenAndServe() error {
  ...省略判斷連線關閉或地址爲空的邏輯的邏輯
   //監聽該地址
   ln, err := net.Listen("tcp", addr)
   if err != nil {
      return err
   }
   //處理請求
   return srv.Serve(ln)
}

省略其中一大串花裏胡哨的解析包裝呼叫跳轉之後,我們來到了最終的目的地

func (srv *Server) Serve(l net.Listener) error {
    for {
        //程式會阻塞在這直到有請求過來
		rw, err := l.Accept()
        ...省略花裏胡哨的錯誤處理邏輯
		c := srv.newConn(rw)
		c.setState(c.rwc, StateNew) // before Serve can return
        //最後使用處理連線請求。因爲每一個連線都開起了一個協程,請求的上下文都不同,同時又保證了go的高併發
        //serve太長了就不貼了
		go c.serve(connCtx)
	}
}
// Create new connection from rwc.
func (srv *Server) newConn(rwc net.Conn) *conn {
   c := &conn{
      // server is the server on which the connection arrived.
	  // Immutable; never nil.
      server: srv,
      // rwc is the underlying network connection.
	  // This is never wrapped by other types and is the value given out
	  // to CloseNotifier callers. It is usually of type *net.TCPConn or
	  // *tls.Conn.
      rwc:    rwc,
   }
   if debugServerConnections {
      c.rwc = newLoggingConn("server", c.rwc)
   }
   return c
}

在这里插入图片描述

最後歡迎大家給我提建議
(本人思維比較混亂…