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)})}
// 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,然后内部按顺序做了以下事情:
- 调用了DefaultServeMux的HandleFunc方法
- 调用了DefaultServeMux的Handle方法
- 往DefaultServeMux的map[string]muxEntry中增加对应的handler和路由规则
- 其次调用http.ListenAndServe(":8080", nil),依次做了以下事情
- 实例化Server
- 调用net.Listen("tcp", addr)监听端口
- 启动一个for循环,在循环体中Accept请求
- 对每个请求实例化一个Conn,并且开启一个goroutine为这个请求进行服务c.serve(ctx)
- 读取每个请求的内容w, err := c.readRequest()
- 判断handler是否为空,如果没有设置handler(这个例子就没有设置handler),handler就设置为DefaultServeMux
- 调用handler的ServeHTTP
- 在这个例子中,下面就进入到DefaultServeMux.ServeHTTP
- 根据request选择handler,并且进入到这个handler的ServeHTTP
- 选择handler:
- 判断是否有路由能满足这个request(循环遍历ServerMux的muxEntry)
- 如果有路由满足,调用这个路由handler的ServeHTTP
- 如果没有路由满足,调用NotFoundHandler的ServeHTTP
阅读全文
0 0
- golang net/http源码解读
- golang http server源码解读
- golang-net/http源码分析之http server
- Golang中net/http包源码分析与解释
- go程序包源码解读——golang.org/x/net/context
- Golang Http Server源码阅读
- Golang Http Server源码阅读
- Golang Http Server源码阅读
- golang net/http包使用
- 简单阅读golang的net/http包和Negroni的源码
- AKKA-HTTP DSL源码解读
- golang的http client源码简析
- golang http server 源码解析与说明
- Go语言net/http 解读.
- caffe源码解读之net
- golang中net/http包用法
- golang中net/http包用法
- Golang学习之net/http包
- 面试题25 :二叉树中和为某一值的路径
- Oracle数据库数据字典概论
- asp.net mvc filter
- java时间段增加、减少工具(含代码)
- web.xml中出现<servlet-name>default</servlet-name>是什么意思?
- golang net/http源码解读
- 我的链接
- 动态规划--最大乘积子序列
- 新的开始
- PostgreSQL data下有哪些目录
- 大型互联网技术架构3-分布式存储-I
- js 禁止用户复制页面内容和修改html
- 基于redux的前端框架dva入门教程
- 通过sql语句恢复数据库