前面介紹了若是經過Go搭建一個web服務,咱們能夠看到簡單應用一個net/http包就方便的搭建起來了。那麼Go在底層究竟是怎麼作的呢?web
Web工做方式的幾個概念服務器
如下均是服務器端的幾個概念cookie
Request:用戶請求的信息,用來解析用戶的請求信息,包括post,get,cookie,url等信息併發
Response:服務器須要反饋給客戶端的信息tcp
Conn:用戶的每次請求連接函數
Handler:處理請求和成成返回信息的處理邏輯高併發
分析http包運行機制post
以下圖所示,是Go實現Web服務的工做模式的流程圖url
http包執行流程:3d
這整個的過程裏面咱們只要瞭解清楚下面三個問題,也就知道Go是如何讓web運行起來了
前面小結的代碼裏咱們能夠看到,Go是經過一個函數ListenAndServe來處理這些事情的,這個底層實際上是這樣處理的:初始化一個server對象,而後調用了net.Listen("tcp",addr),也就是底層用TCP協議單間了一個服務,而後監控咱們設置的端口。
下面這段代碼來自Go的http包的源碼,經過下面的代碼咱們能夠看到整個的http處理過程:
監控以後如何接收客戶端的請求呢?上面代碼執行監控端口以後,調用了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("/",sayhello)麼。這個做用就是註冊了請求/的路由規則,當請求爲"/",路由就會跳轉到函數sayhello,DefaultServeMux會調用ServeHTTP方法,這個方法內部其實就是調用sayhello自己,最後經過寫入response的信息反饋到客戶端。