源码展示
这里展示了 net/http 包的两个接口的源码:ListenAndServe、Serve
ListenAndServe接口做了以下事情:
- 设置地址类型
- 生成侦听器
- 开启Serve
func (srv *Server) ListenAndServe() error { if srv.shuttingDown() { return ErrServerClosed } addr := srv.Addr if addr == "" { addr = ":http" } ln, err := net.Listen("tcp", addr) if err != nil { return err } return srv.Serve(ln) }
Serve接口做了以下事情:
- 检查是否有 server hook,有的话执行
- 复制 listener
- 设置 http2
- trackListener,用于关闭时使用
- 设置 baseCtx
- 开启循环,监听接口,建立链接,给链接设置状态,然后为每个链接生成一个 goroutine 来循环执行请求
1 func (srv *Server) Serve(l net.Listener) error { 2 if fn := testHookServerServe; fn != nil { 3 fn(srv, l) // call hook with unwrapped listener 4 } 5 6 origListener := l 7 l = &onceCloseListener{Listener: l} 8 defer l.Close() 9 10 if err := srv.setupHTTP2_Serve(); err != nil { 11 return err 12 } 13 14 if !srv.trackListener(&l, true) { 15 return ErrServerClosed 16 } 17 defer srv.trackListener(&l, false) 18 19 baseCtx := context.Background() 20 if srv.BaseContext != nil { 21 baseCtx = srv.BaseContext(origListener) 22 if baseCtx == nil { 23 panic("BaseContext returned a nil context") 24 } 25 } 26 27 var tempDelay time.Duration // how long to sleep on accept failure 28 29 ctx := context.WithValue(baseCtx, ServerContextKey, srv) 30 for { 31 rw, err := l.Accept() 32 if err != nil { 33 select { 34 case <-srv.getDoneChan(): 35 return ErrServerClosed 36 default: 37 } 38 if ne, ok := err.(net.Error); ok && ne.Temporary() { 39 if tempDelay == 0 { 40 tempDelay = 5 * time.Millisecond 41 } else { 42 tempDelay *= 2 43 } 44 if max := 1 * time.Second; tempDelay > max { 45 tempDelay = max 46 } 47 srv.logf("http: Accept error: %v; retrying in %v", err, tempDelay) 48 time.Sleep(tempDelay) 49 continue 50 } 51 return err 52 } 53 connCtx := ctx 54 if cc := srv.ConnContext; cc != nil { 55 connCtx = cc(connCtx, rw) 56 if connCtx == nil { 57 panic("ConnContext returned nil") 58 } 59 } 60 tempDelay = 0 61 c := srv.newConn(rw) 62 c.setState(c.rwc, StateNew) // before Serve can return 63 go c.serve(connCtx) 64 } 65 }
缺陷
- 每个 connection 都生成 goroutine 来执行,goroutine 的数量会不可控,如果数量过多的话会导致调度效率降低,利用率低等情况