go語言http server解析之一

go server

image.png
圖片模仿build web application with golang,學習畫圖技巧。git

經過學習發現go寫http server主要有如下兩種方式,本文是分析beego中的httpServer和graceServer的基礎前提。經過分析源碼,和unix中開發server中的方式(socket,bind,listen,accetp)串連起來,而不單單是go給咱們提供好的幾個api。

方式1:ServeHTTP方式

package main

import (
    "log"
    "net/http"
)

type sayHandler struct {
}

func (h *sayHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("hello"))

}

func main() {
    log.Fatal(http.ListenAndServe(":8080", new(sayHandler)))
}

code-1-1github

方式2:handleFunc方式

// Package main provides ...
package main

import (
    "log"
    "net/http"
)

func say(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("hello world"))
}

func main() {
    http.HandleFunc("/hello", say)
    log.Fatal(http.ListenAndServe(":8080", nil))
}

code-1-2golang

源碼解析

先分析code-1-1中的代碼,從ListenAndServe開始web

func ListenAndServe(addr string, handler Handler) error {
    server := &Server{Addr: addr, Handler: handler}
    return server.ListenAndServe()
}

code-1-3
看下Serverapi

type Server struct {
    Addr    string  
    Handler Handler 
    ...
}

code-1-4
繼續看下Handlerapp

type Handler interface {
    ServeHTTP(ResponseWriter, *Request)
}

code-1-5
這裏咱們看到ListenAndServe第二個參數只要實現code-1-5中的接口就能夠了。
咱們回到code-1-3中繼續分析。socket

func (srv *Server) ListenAndServe() error {
    ....
    ln, err := net.Listen("tcp", addr)
    ....
    return srv.Serve(ln)
}

code-1-6
這裏調用了Listen,繼續下tcp

func (srv *Server) Serve(l net.Listener) error {
    ....
    for {
        rw, e := l.Accept()
        ...
        c := srv.newConn(rw)
        c.setState(c.rwc, StateNew)
        go c.serve(ctx)
    }
}

code-1-7
這裏調用了Accetp,獲得了socket鏈接。
看一下newConn,這個主要是封裝下,能夠讀取server的方法。go c.serve(ctx)能夠每一個鏈接一個協程處理。ide

func (srv *Server) newConn(rwc net.Conn) *conn {
    c := &conn{
        server: srv,
        rwc:    rwc,
    }
    ...
    return c
}

code-1-8學習

// Serve a new connection.
func (c *conn) serve(ctx context.Context) {
    ...
    for {
        w, err := c.readRequest(ctx)
        
        ...
    
        serverHandler{c.server}.ServeHTTP(w, w.req)
        ...
}

code-1-9

serverHandler{c.server}.ServeHTTP(w, w.req)會調用ServeHTTP方法。若是調用時傳了Handler,則調用Handler的Serve。到如今咱們回答了code-1-1中的問題了。

type serverHandler struct {
    srv *Server
}

func (sh serverHandler) ServeHTTP(rw ResponseWriter, req *Request) {
    handler := sh.srv.Handler
    if handler == nil {
        handler = DefaultServeMux
    }
    if req.RequestURI == "*" && req.Method == "OPTIONS" {
        handler = globalOptionsHandler{}
    }
    handler.ServeHTTP(rw, req)
}

code-1-10

code-1-2中的代碼使用的是DefaultServeMux,咱們下篇文章分析。

參考連接

http-servers
function handler
build-web-application-with-golang

相關文章
相關標籤/搜索