【简单的HTTP服务器】
源文件server.go中 ListenAndServe()函数的注释中有个简单的HTTP服务实现代码,如下
package main
import (
"io"
"log"
"net/http"
)
func HelloServer(w http.ResponseWriter, r *http.Request) {
io.WriteString(w, "hello ,this is from HelloServer func ")
}
func main() {
http.HandleFunc("/hello", HelloServer)
log.Fatal(http.ListenAndServe(":12345", nil))
}
【func (srv *Server) Serve(l net.Listener) 方法】
之前有梳理过http.ListenAndServe() 最终会调用 Server类型的Serve()方法。再看下其源码如下 net/http/server.go 中
2678 func (srv *Server) Serve(l net.Listener) error {
2679 defer l.Close()
2680 if fn := testHookServerServe; fn != nil {
2681 fn(srv, l)
2682 }
2683 var tempDelay time.Duration // how long to sleep on accept failure
2684
2685 if err := srv.setupHTTP2_Serve(); err != nil {
2686 return err
2687 }
2688
2689 srv.trackListener(l, true)
2690 defer srv.trackListener(l, false)
2691
2692 baseCtx := context.Background() // base is always background, per Issue 16220
2693 ctx := context.WithValue(baseCtx, ServerContextKey, srv)
2694 for {
2695 rw, e := l.Accept()
2696 if e != nil {
2697 select {
2698 case <-srv.getDoneChan():
2699 return ErrServerClosed
2700 default:
2701 }
2702 if ne, ok := e.(net.Error); ok && ne.Temporary() {
2703 if tempDelay == 0 {
2704 tempDelay = 5 * time.Millisecond
2705 } else {
2706 tempDelay *= 2
2707 }
2708 if max := 1 * time.Second; tempDelay > max {
2709 tempDelay = max
2710 }
2711 srv.logf("http: Accept error: %v; retrying in %v", e, tempDelay)
2712 time.Sleep(tempDelay)
2713 continue
2714 }
2715 return e
2716 }
2717 tempDelay = 0
2718 c := srv.newConn(rw)
2719 c.setState(c.rwc, StateNew) // before Serve can return
2720 go c.serve(ctx)
2721 }
2722 }
第2683行定义了一个 time.Duration 类型的局部变量,用于控制 accept失败后的等待时间。后续的select语句会用到。
var tempDelay time.Duration // how long to sleep on accept failure
2689 srv.trackListener(l, true)
2690 defer srv.trackListener(l, false)
源码如下,调用了Server类型的trackListener()方法,私有函数,用于对 *Server 数据的并发保护,s.listeners为Server类型的成员变量,类型是一个map,key为 net.Listener ,value为 Struce{}。 Server 类型可以是零值的,所以在使用listeners 成员的时候 要做个nil的判断,通过make()内置函数初始化。
2767 func (s *Server) trackListener(ln net.Listener, add bool) {
2768 s.mu.Lock()
2769 defer s.mu.Unlock()
2770 if s.listeners == nil {
2771 s.listeners = make(map[net.Listener]struct{})
2772 }
2773 if add {
2774 // If the *Server is being reused after a previous
2775 // Close or Shutdown, reset its doneChan:
2776 if len(s.listeners) == 0 && len(s.activeConn) == 0 {
2777 s.doneChan = nil
2778 }
2779 s.listeners[ln] = struct{}{}
2780 } else {
2781 delete(s.listeners, ln)
2782 }
2783 }
接下来的for循环,源码如下
2694 for {
2695 rw, e := l.Accept()
2696 if e != nil {
2697 select {
2698 case <-srv.getDoneChan():
2699 return ErrServerClosed
2700 default:
2701 }
2702 if ne, ok := e.(net.Error); ok && ne.Temporary() {
2703 if tempDelay == 0 {
2704 tempDelay = 5 * time.Millisecond
2705 } else {
2706 tempDelay *= 2
2707 }
2708 if max := 1 * time.Second; tempDelay > max {
2709 tempDelay = max
2710 }
2711 srv.logf("http: Accept error: %v; retrying in %v", e, tempDelay)
2712 time.Sleep(tempDelay)
2713 continue
2714 }
2715 return e
2716 }
2717 tempDelay = 0
2718 c := srv.newConn(rw)
2719 c.setState(c.rwc, StateNew) // before Serve can return
2720 go c.serve(ctx)
主要做了5件事情
- 通过Accept() 监听请求
- Accpet错误处理
- 通过Server类型的newConn方法构建 conn类型数据(小写c)
- 设置conn状态
- 并发执行conn
1、l.Accept() 默认是执行net.Listener 接口的 Accept() 方法,即: Accept() (Conn, error)
之前梳理 ListenAndServe的时候,有个tcpKeepAliveListener 类型的数据,重新实现了Accept方法,增加了超时时间的设置。
2、通过select语句实现错误等待。case阻塞后,会执行default语句。通过Temporary()简单判断
3、 c := srv.newConn(rw) 中 newConn()方法代码如下,构造conn类型。
func (srv *Server) newConn(rwc net.Conn) *conn {
c := &conn{
server: srv,
rwc: rwc,
}
if debugServerConnections {
c.rwc = newLoggingConn("server", c.rwc)
}
return c
}
conn类型为server.go 中的私有类型,较复杂,需要了解的直接看源码
4、c.setState(c.rwc, StateNew) 设置conn的状态,setState()源码如下,根据参数state的值来设置状态
1634 func (c *conn) setState(nc net.Conn, state ConnState) {
1635 srv := c.server
1636 switch state {
1637 case StateNew:
1638 srv.trackConn(c, true)
1639 case StateHijacked, StateClosed:
1640 srv.trackConn(c, false)
1641 }
1642 c.curState.Store(connStateInterface[state])
1643 if hook := srv.ConnState; hook != nil {
1644 hook(nc, state)
1645 }
1646 }
参数state的数值如下:
var stateName = map[ConnState]string{
StateNew: "new",
StateActive: "active",
StateIdle: "idle",
StateHijacked: "hijacked",
StateClosed: "closed",
5、go c.serve(ctx)并发执行 请求。其原型如下 func (c *conn) serve(ctx context.Context)。源码逻辑较复杂,我们值关注下面这行,即 ServeHTTP(w, w.req)。
1794 // HTTP cannot have multiple simultaneous active requests.[*]
1795 // Until the server replies to this request, it can't read another,
1796 // so we might as well run the handler in this goroutine.
1797 // [*] Not strictly true: HTTP pipelining. We could let them all process
1798 // in parallel even if their responses need to be serialized.
1799 // But we're not going to implement HTTP pipelining because it
1800 // was never deployed in the wild and the answer is HTTP/2.
1801 serverHandler{c.server}.ServeHTTP(w, w.req)
回到开始的例子,HelloServer(w http.ResponseWriter, r *http.Request) 的签名与 ServeHTTP(w, w.req)是一致的.即 ListerAndServe → Server.Serve() → conn.serve 最后执行 ServeHTTP(w, w.req) 签名格式的逻辑,在本例中就是HelloServer自定义函数。最终HTTP的通信通过Request 和Response 来实现。