golang net/http源码解读

来源:互联网 发布:js css 编辑:程序博客网 时间:2024/06/05 19:21

一、一个简单的web服务器

import (    "io"    "log"    "net/http")func HelloGoServer(w http.ResponseWriter, req *http.Request) {    io.WriteString(w, "Hello, this is a GoServer")}func main() {    http.HandleFunc("/", HelloGoServer)    err := http.ListenAndServe(":9090", nil)    if err != nil {        log.Fatal("ListenAndServer ", err)    }}

二、net/http包源码解析

由上述看出实现一个简单的web服务器,仅仅需要几行的代码,可以说 http.HandleFunc("/", HelloGoServer)    http.ListenAndServe(":9090", nil)两句代码几乎撑起整个服务器的建设。那么就具体来分析这两个函数的具体实现。

1、分析http.HandleFunc(),先看看源码中的定义

// HandleFunc registers the handler function for the given pattern// in the DefaultServeMux.// The documentation for ServeMux explains how patterns are matched.func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {    DefaultServeMux.HandleFunc(pattern, handler)}

可以看出调用了DefaultServeMux的HandleFunc()函数

再看看DefaultServeMux

type ServeMux struct {    mu    sync.RWMutex //锁,由于请求涉及到并发处理,因此这里需要一个锁机制    m     map[string]muxEntry  // 路由规则,一个string对应一个mux实体,这里的string就是注册的路由表达式    hosts bool // whether any patterns contain hostnames}type muxEntry struct {    explicit bool // 是否精确匹配    h        Handler // 这个路由表达式对应哪个handler    pattern  string //匹配字符串}// NewServeMux allocates and returns a new ServeMux.func NewServeMux() *ServeMux { return new(ServeMux) }// DefaultServeMux is the default ServeMux used by Serve.var DefaultServeMux = &defaultServeMuxvar defaultServeMux ServeMux// Handle registers the handler for the given pattern.// If a handler already exists for pattern, Handle panics.func (mux *ServeMux) Handle(pattern string, handler Handler)// HandleFunc registers the handler function for the given pattern.func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request))// ServeHTTP dispatches the request to the handler whose// pattern most closely matches the request URL.func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request)

先看看这些函数的相互调用关系

http.HandleFunc-->  func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request))

-->func (mux *ServeMux) Handle(pattern string, handler Handler)

func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {    mux.Handle(pattern, HandlerFunc(handler))}

// Handle registers the handler for the given pattern.// If a handler already exists for pattern, Handle panics.func (mux *ServeMux) Handle(pattern string, handler Handler) {    mux.mu.Lock()    defer mux.mu.Unlock()    if pattern == "" {        panic("http: invalid pattern " + pattern)    }    if handler == nil {        panic("http: nil handler")    }    if mux.m[pattern].explicit {        panic("http: multiple registrations for " + pattern)    }    if mux.m == nil {        mux.m = make(map[string]muxEntry)    }    mux.m[pattern] = muxEntry{explicit: true, h: handler, pattern: pattern}    if pattern[0] != '/' {        mux.hosts = true    }    // Helpful behavior:    // If pattern is /tree/, insert an implicit permanent redirect for /tree.    // It can be overridden by an explicit registration.    n := len(pattern)    if n > 0 && pattern[n-1] == '/' && !mux.m[pattern[0:n-1]].explicit {        // If pattern contains a host name, strip it and use remaining        // path for redirect.        path := pattern        if pattern[0] != '/' {            // In pattern, at least the last character is a '/', so            // strings.Index can't be -1.            path = pattern[strings.Index(pattern, "/"):]        }        url := &url.URL{Path: path}        mux.m[pattern[0:n-1]] = muxEntry{h: RedirectHandler(url.String(), StatusMovedPermanently), pattern: pattern}    }}

可以看出注册的过程其实就是构造map[string] muxEntry这个map或者往已有的里面添加值,key是url,value是处理函数以及其他一些必要信息。



2、分析http.ListenAndServe

先看定义

func ListenAndServe(addr string, handler Handler) error {    server := &Server{Addr: addr, Handler: handler}    return server.ListenAndServe()}
利用参数addr和handler创建一个Server类型的变量server,然后调用这个结构体里的成员函数ListenAndServe(),

先看看结构体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 address to listen on, ":http" if empty    Handler      Handler       // handler to invoke, http.DefaultServeMux if nil    ReadTimeout  time.Duration // maximum duration before timing out read of the request    WriteTimeout time.Duration // maximum duration before timing out write of the response    TLSConfig    *tls.Config   // optional TLS config, used by ListenAndServeTLS    // MaxHeaderBytes controls the maximum number of bytes the    // server will read parsing the request header's keys and    // values, including the request line. It does not limit the    // size of the request body.    // If zero, DefaultMaxHeaderBytes is used.    MaxHeaderBytes int    // TLSNextProto optionally specifies a function to take over    // ownership of the provided TLS connection when an NPN/ALPN    // protocol upgrade has occurred. The map key is the protocol    // name negotiated. The Handler argument should be used to    // handle HTTP requests and will initialize the Request's TLS    // and RemoteAddr if not already set. The connection is    // automatically closed when the function returns.    // If TLSNextProto is nil, HTTP/2 support is enabled automatically.    TLSNextProto map[string]func(*Server, *tls.Conn, Handler)    // ConnState specifies an optional callback function that is    // called when a client connection changes state. See the    // ConnState type and associated constants for details.    ConnState func(net.Conn, ConnState)    // ErrorLog specifies an optional logger for errors accepting    // connections and unexpected behavior from handlers.    // If nil, logging goes to os.Stderr via the log package's    // standard logger.    ErrorLog *log.Logger    disableKeepAlives int32     // accessed atomically.    nextProtoOnce     sync.Once // guards setupHTTP2_* init    nextProtoErr      error     // result of http2.ConfigureServer if used}
再看看成员函数ListenAndServe(),它的作用是监听srv.Addr指定的TCP网络,并且调用srv.Serve()函数来处理收到的请求

// ListenAndServe listens on the TCP network address srv.Addr and then// calls Serve to handle requests on incoming connections.// Accepted connections are configured to enable TCP keep-alives.// If srv.Addr is blank, ":http" is used.// ListenAndServe always returns a non-nil error.func (srv *Server) ListenAndServe() error {    addr := srv.Addr    if addr == "" {        addr = ":http"    }    ln, err := net.Listen("tcp", addr)    if err != nil {        return err    }    return srv.Serve(tcpKeepAliveListener{ln.(*net.TCPListener)})}


srv.Serve()

// Serve accepts incoming connections on the Listener l, creating a// new service goroutine for each. The service goroutines read requests and// then call srv.Handler to reply to them.//// For HTTP/2 support, srv.TLSConfig should be initialized to the// provided listener's TLS Config before calling Serve. If// srv.TLSConfig is non-nil and doesn't include the string "h2" in// Config.NextProtos, HTTP/2 support is not enabled.//// Serve always returns a non-nil error.func (srv *Server) Serve(l net.Listener) error {    defer l.Close()    if fn := testHookServerServe; fn != nil {        fn(srv, l)    }    var tempDelay time.Duration // how long to sleep on accept failure    if err := srv.setupHTTP2_Serve(); err != nil {        return err    }    // TODO: allow changing base context? can't imagine concrete    // use cases yet.    baseCtx := context.Background()    ctx := context.WithValue(baseCtx, ServerContextKey, srv)    ctx = context.WithValue(ctx, LocalAddrContextKey, l.Addr())    for {        rw, e := l.Accept()        if e != nil {            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        c := srv.newConn(rw)        c.setState(c.rwc, StateNew) // before Serve can return        go c.serve(ctx)    }}


3、整体流程

(1)、首先调用http.HandleFunc,然后内部按顺序做了以下事情:

  1. 调用了DefaultServeMux的HandleFunc方法
  2. 调用了DefaultServeMux的Handle方法
  3. 往DefaultServeMux的map[string]muxEntry中增加对应的handler和路由规则
  4. 其次调用http.ListenAndServe(":8080", nil),依次做了以下事情
  5. 实例化Server
(2)、调用Server的ListenAndServe方法


  1. 调用net.Listen("tcp", addr)监听端口
  2. 启动一个for循环,在循环体中Accept请求
  3. 对每个请求实例化一个Conn,并且开启一个goroutine为这个请求进行服务c.serve(ctx)
  4. 读取每个请求的内容w, err := c.readRequest()
  5. 判断handler是否为空,如果没有设置handler(这个例子就没有设置handler),handler就设置为DefaultServeMux
  6. 调用handler的ServeHTTP
  7. 在这个例子中,下面就进入到DefaultServeMux.ServeHTTP
  8. 根据request选择handler,并且进入到这个handler的ServeHTTP
  9. 选择handler:
  10. 判断是否有路由能满足这个request(循环遍历ServerMux的muxEntry)
  11. 如果有路由满足,调用这个路由handler的ServeHTTP
  12. 如果没有路由满足,调用NotFoundHandler的ServeHTTP


原创粉丝点击