func (srv *Server) Serve(l net.Listener) error {defer l.Close()
var tempDelay time.Duration // how long to sleep on accept failure
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
}
log.Printf("http: Accept error: %v; retrying in %v", e, tempDelay)
time.Sleep(tempDelay)
continue
}
return e
}
tempDelay = 0
if srv.ReadTimeout != 0 {
rw.SetReadDeadline(time.Now().Add(srv.ReadTimeout))
}
if srv.WriteTimeout != 0 {
rw.SetWriteDeadline(time.Now().Add(srv.WriteTimeout))
}
c, err := srv.newConn(rw)
if err != nil {
continue
}
go c.serve()
}
panic("not reached")
}
監控以後如何接收客戶端的請求呢?上面代碼執行監控端口以後,調用了srv.Serve(net.Listener)函數,這個函數就是處理接收客戶端的請求信息。這個函數裏面起了一個 for{},首先經過 Listener 接收請求,其次建立一個 Conn,最後單獨開了一個goroutine,
把這個請求的數據當作參數扔給這個 conn 去服務:go c.serve()。這個就是高併發體現了,用戶的每次請求都是在一個新的 goroutine 去服務,相互不影響。那麼如何具體分配到相應的函數來處理請求呢?
conn 首先會解析 request:c.readRequest(),而後獲取相應的 handler:handler := c.server.Handler,也就是咱們剛纔在調用函數ListenAndServe 時候的第二個參數,咱們前面例子傳遞的是 nil,也就是爲空,那麼默認獲取 handler = DefaultServeMux,那麼這個變量用來作什麼的呢?對,這個變量就是一個路由器,它用來匹配 url 跳轉到其相應的 handle 函數,那麼這個咱們有設置過嗎?有,咱們調用的代碼裏面第一句不是調用了 http.HandleFunc("/", sayhelloName)嘛。
這個做用就是註冊了請求/的路由規則,當請求 uri 爲"/",路由就會轉到函數 sayhelloName,DefaultServeMux會調用 ServeHTTP 方法,這個方法內部其實就是調用 sayhelloName 自己,最後經過寫入response 的信息反饋到客戶端。
Go 的 http 有兩個核心功能:Conn、ServeMux
type Handler interface {
ServeHTTP(ResponseWriter, *Request) // 路由實現器
}
Handler 是一個接口,可是前一小節中的 sayhelloName 函數並無實現 ServeHTTP 這個接口,爲何能添加呢?原來在 http 包裏面還定義了一個類型 HandlerFunc,咱們定義的函 數 sayhelloName 就是這個 HandlerFunc 調用以後的結果,這個類型默認就實現了ServeHTTP 這個接口,即咱們調用了 HandlerFunc(f),強制類型轉換 f 成爲 HandlerFunc 類型,這樣 f 就擁有了 ServHTTP 方法。
type HandlerFunc func(ResponseWriter, *Request)
// ServeHTTP calls f(w, r)
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
f(w, r)
}
按順序作了幾件事:
1 調用了 DefaultServerMux 的 HandleFunc
2 調用了 DefaultServerMux 的 Handle3 往 DefaultServeMux 的 map[string]muxEntry 中增長對應的 handler 和路由規則
• 其次調用 http.ListenAndServe(":9090", nil)
按順序作了幾件事情:
1 實例化 Server
2 調用 Server 的 ListenAndServe()
3 調用 net.Listen("tcp", addr)監聽端口
4 啓動一個 for 循環,在循環體中 Accept 請求
5 對每一個請求實例化一個 Conn,而且開啓一個 goroutine 爲這個請求進行服務 go c.serve()
6 讀取每一個請求的內容 w, err := c.readRequest()
7 判斷 handler 是否爲空,若是沒有設置 handler(這個例子就沒有設置
handler),handler 就設置爲 DefaultServeMux
8 調用 handler 的 ServeHttp
9 在這個例子中,下面就進入到 DefaultServerMux.ServeHttp
10 根據 request 選擇 handler,而且進入到這個 handler 的 ServeHTTP
mux.handler(r).ServeHTTP(w, r)
11 選擇 handler:
A 判斷是否有路由能知足這個 request(循環遍歷 ServerMux 的 muxEntry)
B 若是有路由知足,調用這個路由 handler 的 ServeHttp
C 若是沒有路由知足,調用 NotFoundHandler 的 ServeHttp