ListenAndServe源碼剖析

使用goland追蹤閱讀ListenAndServe源碼,剖析服務器啓動流程

  • ListenAndServe閱讀web

func ListenAndServe(addr string, handler Handler) error {
    //1. 建立server
	server := &Server{Addr: addr, Handler: handler}
    //2. 啓動server
	return server.ListenAndServe()
}

 注意:建立一個server,啓動server,咱們也能夠按照這2個步驟去建立一個web服務安全

  • Server結構閱讀服務器

// 基類Closer接口,關閉全部連接中止服務
type Closer interface {
	Close() error
}

// 檢查服務是否存活,裏面定義了接口,接口的另類定義使用
// 奇怪的行爲,不肯定爲何這麼作
func http2h1ServerKeepAlivesDisabled(hs *Server) bool {
	var x interface{} = hs
    // 臨時定義接口,使用【奇怪的使用方法】
	type I interface {
		doKeepAlives() bool
	}
	if hs, ok := x.(I); ok {
		return !hs.doKeepAlives()
	}
	return false
}


//Server
// A Server defines parameters for running an HTTP server.
// The zero value for Server is a valid configuration.
type Server struct {
	Addr    string  // 監聽的TCP地址
	Handler Handler // 註冊的路由處理方法

	// 若是服務須要支持https協議 那麼須要相應的配置
	TLSConfig *tls.Config

	//讀超時設置
	ReadTimeout time.Duration

	// 讀取請求頭超時設置
	ReadHeaderTimeout time.Duration

	// 寫超時
	WriteTimeout time.Duration

	// 請求直接最長的空閒時長
	IdleTimeout time.Duration

	// 請求頭最大的容量
	MaxHeaderBytes int

	// HTTPS協議相關
	TLSNextProto map[string]func(*Server, *tls.Conn, Handler)

	// 能夠添回調函數,當客戶端處於哪一個狀態時候能夠執行某些動做
	ConnState func(net.Conn, ConnState)

	// 錯誤日誌器,不設置默認使用內置logger模塊
	ErrorLog *log.Logger
	
  	//原子操做,是否保持長鏈接
	disableKeepAlives int32     // accessed atomically.
    //原子操做,服務要關閉了
	inShutdown        int32     // accessed atomically (non-zero means we're in Shutdown)
    // https相關操做 用於初始化
	nextProtoOnce     sync.Once // guards setupHTTP2_* init
	nextProtoErr      error     // result of http2.ConfigureServer if used
	// 互斥鎖 保證資源的安全
	mu         sync.Mutex
  // 服務套接字表,監聽socket表
	listeners  map[*net.Listener]struct{}
  // 存活的客戶端連接表
	activeConn map[*conn]struct{}
  //用於通知服務關閉了
	doneChan   chan struct{}
    
  // 註冊服務器關閉執行的一些行爲
	onShutdown []func()
}

 

注意:通常建立server只須要Addr與handler便可app

  • ListenAndServe閱讀socket

    監聽並啓動服務tcp

func (srv *Server) ListenAndServe() error {
    // 判斷服務器是否是已經關閉了
	if srv.shuttingDown() {
		return ErrServerClosed
	}
    // 獲取要綁定監聽的地址
	addr := srv.Addr
	if addr == "" {
		addr = ":http"
	}
    // 建立用於監監聽socket連接
	ln, err := net.Listen("tcp", addr)
	if err != nil {
		return err
	}
    // tcpKeepAliveListener 設置監聽超時,在accept的時不會一直阻塞 設置一個超時操做
  //啓動服務
	return srv.Serve(tcpKeepAliveListener{ln.(*net.TCPListener)})
}

 srv.Serve源碼閱讀函數

func (srv *Server) Serve(l net.Listener) error {
    // 測試用的鉤子函數,其餘時候沒有用的
	if fn := testHookServerServe; fn != nil {
		fn(srv, l) // call hook with unwrapped listener
	}
	// sync.once 建立一個once對象,用於防止屢次關閉連接
	l = &onceCloseListener{Listener: l}
    // 結束的時候關閉監聽socket
	defer l.Close()
	
   	// 設置http2相關的設置
	if err := srv.setupHTTP2_Serve(); err != nil {
		return err
	}
	
    // 把監聽socket添加監聽表
	if !srv.trackListener(&l, true) {
		return ErrServerClosed
	}
    // 結束的時候從監聽表刪除
	defer srv.trackListener(&l, false)
	
    // 設置臨時過時時間,當accept發生 錯誤的時候等待一段時間
	var tempDelay time.Duration     // how long to sleep on accept failure
    // 設置context 主要用於取消任務
	baseCtx := context.Background() // base is always background, per Issue 16220
    // 注意ctx把server自己傳遞進去了,用於傳遞
	ctx := context.WithValue(baseCtx, ServerContextKey, srv)
    // 循環監聽客戶端到來
	for {
        // accept 阻塞等待客戶單到來
		rw, e := l.Accept()
        // 錯誤後處理邏輯
		if e != nil {
            // 嘗試檢查下服務是否是關閉了
			select {
            // 關閉則返回錯誤
			case <-srv.getDoneChan():
				return ErrServerClosed
			default:
			}
            // 檢查錯誤類型,若是是連接被重置
			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爲0
		tempDelay = 0
        // 建立server鏈接,server鏈接包含了與客戶端通信的socket以及server相關的信息
		c := srv.newConn(rw)
        // 更新連接狀態
		c.setState(c.rwc, StateNew) // before Serve can return
        // 啓動goroutine處理socket
		go c.serve(ctx)
	}
}

 server conn結構體閱讀post

// 服務端連接結構體
type conn struct {
	// 連接綁定服務
	server *Server
	
	// 用於取消任務的ctxFunc
	cancelCtx context.CancelFunc

	// socket 通信用的底層socket
	rwc net.Conn

    // 客戶端地址127.0.0.0:5678
	remoteAddr string

	// tls 狀態
	tlsState *tls.ConnectionState

	// werr is set to the first write error to rwc.
	// 第一次寫出現錯誤的時候設置
	werr error

	// r is bufr's read source. 
	// 用於讀取請求的對象,主要用於讀取數據的
	r *connReader

	// bufr reads from r.
    // r讀取的數據存儲buf
	bufr *bufio.Reader

	// bufw writes to checkConnErrorWriter{c}, which populates werr on error.
    // 寫buf
	bufw *bufio.Writer

	// lastMethod is the method of the most recent request
	// on this connection, if any.
    // 最後一次請求,方法 是post仍是其餘等
	lastMethod string
	
    // 當前的請求
	curReq atomic.Value // of *response (which has a Request in it)
	
    // 當前cnn狀態
	curState struct{ atomic uint64 } // packed (unixtime<<8|uint8(ConnState))

	//保護hijackedv
	mu sync.Mutex

	// hijackedv is whether this connection has been hijacked
    //表示是否支持用戶劫持連接【主要用於切換協議的】
	hijackedv bool
}

ListenAndServe調用圖示

相關文章
相關標籤/搜索