golang-net/http源码分析之http server
2016-12-12 15:52
836 查看
本文csdn博客链接:http://blog.csdn.net/screscent/article/details/53583764
本文qq空间链接:http://user.qzone.qq.com/29185807/blog/1481529299
创建一个http server,简单的几条语句就可以了。
其中的接口部分如下
ServerMux则是一个http路由struct。里面的map包含了一个路由hash表。
另外上面的代码中,也形成了一个DefaultServeMux,默认的路由对象。
下面一个一个来做函数分析
这个函数为注册路由表函数,功能就是创建muxEntry,然后将其放入到路由map中
其实是创建了一个Server对象
看看server都提供哪些操作
下面我们跟踪过程
其中Listen返回的是一个Listener接口
步骤:Accept–>srv.newConn–>c.serve(ctx)
链接处理部分,构建一个tcp listener,然后accept,构建conn
然后通过conn,查找路由,找到处理函数,进行处理
龚浩华
qq 29185807 月牙寂-道长
2016年12月12日
本文qq空间链接:http://user.qzone.qq.com/29185807/blog/1481529299
golang-net/http源码分析之http server
1 简介
先看下net/http库中的例子创建一个http server,简单的几条语句就可以了。
http.Handle("/foo", fooHandler) http.HandleFunc("/bar", func(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Hello, %q", html.EscapeString(r.URL.Path)) }) log.Fatal(http.ListenAndServe(":8080", nil))
其中的接口部分如下
type HandlerFunc func(ResponseWriter, *Request)
2 路由
要理解http server那么就应该从路由开始。那么开始看源码type ServeMux struct { mu sync.RWMutex m map[string]muxEntry hosts bool // whether any patterns contain hostnames } type muxEntry struct { explicit bool h 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 = &defaultServeMux var defaultServeMux ServeMux
ServerMux则是一个http路由struct。里面的map包含了一个路由hash表。
另外上面的代码中,也形成了一个DefaultServeMux,默认的路由对象。
type ServeMux func NewServeMux() *ServeMux func (mux *ServeMux) Handle(pattern string, handler Handler) func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) func (mux *ServeMux) Handler(r *Request) (h Handler, pattern string) func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request)
下面一个一个来做函数分析
2.1 Handle
func (mux *ServeMux) Handle(pattern string, handler Handler)
这个函数为注册路由表函数,功能就是创建muxEntry,然后将其放入到路由map中
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}
}
}
2.2 HandleFunc
HandleFunc就是对Handle的封装func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) { mux.Handle(pattern, HandlerFunc(handler)) }
2.3 Handler
Handler则是根据request的访问路径,查找相关的路由表,得到处理函数func (mux *ServeMux) Handler(r *Request) (h Handler, pattern string) { if r.Method != "CONNECT" { if p := cleanPath(r.URL.Path); p != r.URL.Path { _, pattern = mux.handler(r.Host, p) url := *r.URL url.Path = p return RedirectHandler(url.String(), StatusMovedPermanently), pattern } } return mux.handler(r.Host, r.URL.Path) } func (mux *ServeMux) handler(host, path string) (h Handler, pattern string) { mux.mu.RLock() defer mux.mu.RUnlock() // Host-specific pattern takes precedence over generic ones if mux.hosts { h, pattern = mux.match(host + path) } if h == nil { h, pattern = mux.match(path) } if h == nil { h, pattern = NotFoundHandler(), "" } return }
2.4 ServeHTTP
ServerHttp则是路由的入口func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) { //下面是处理url路径 if r.RequestURI == "*" { if r.ProtoAtLeast(1, 1) { w.Header().Set("Connection", "close") } w.WriteHeader(StatusBadRequest) return } //查找handler h, _ := mux.Handler(r) //具体的处理 h.ServeHTTP(w, r) }
2.5 DefaultServeMux
默认路由,只是对DefaultServeMux的一层封装func Handle(pattern string, handler Handler) { DefaultServeMux.Handle(pattern, handler) } func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) { DefaultServeMux.HandleFunc(pattern, handler) }
3 Server
入口,创建并监听。其实是创建了一个Server对象
func ListenAndServe(addr string, handler Handler) error { server := &Server{Addr: addr, Handler: handler} return server.ListenAndServe() }
看看server都提供哪些操作
type Server func (srv *Server) ListenAndServe() error func (srv *Server) ListenAndServeTLS(certFile, keyFile string) error func (srv *Server) Serve(l net.Listener) error func (srv *Server) SetKeepAlivesEnabled(v bool)
下面我们跟踪过程
3.1 ListenAndServe
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)}) }
其中Listen返回的是一个Listener接口
func Listen(net, laddr string) (Listener, error) type Listener interface { // Accept waits for and returns the next connection to the listener. Accept() (Conn, error) // Close closes the listener. // Any blocked Accept operations will be unblocked and return errors. Close() error // Addr returns the listener's network address. Addr() Addr }
3.2 Serve
真正的入口处步骤:Accept–>srv.newConn–>c.serve(ctx)
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 { //调用Accept监听 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) } }
4 conn
4.1 newConn
创建了一个connfunc (srv *Server) newConn(rwc net.Conn) *conn { c := &conn{ server: srv, rwc: rwc, } if debugServerConnections { c.rwc = newLoggingConn("server", c.rwc) } return c }
4.2 serve
conn里读取数据,然后进行处理// Serve a new connection. func (c *conn) serve(ctx context.Context) { c.remoteAddr = c.rwc.RemoteAddr().String() ... c.r = &connReader{r: c.rwc} c.bufr = newBufioReader(c.r) c.bufw = newBufioWriterSize(checkConnErrorWriter{c}, 4<<10) ctx, cancelCtx := context.WithCancel(ctx) defer cancelCtx() for { w, err := c.readRequest(ctx) ... //真正的处理地方 serverHandler{c.server}.ServeHTTP(w, w.req) w.cancelCtx() if c.hijacked() { return } w.finishRequest() if !w.shouldReuseConnection() { if w.requestBodyLimitHit || w.closedRequestBodyEarly() { c.closeWriteAndWait() } return } c.setState(c.rwc, StateIdle) } }
4.3 ServeHTTP
最终的地方。通过寻找路由,找到路由处理函数,然后对请求信息做响应处理。type serverHandler struct { srv *Server } func (sh serverHandler) ServeHTTP(rw ResponseWriter, req *Request) { handler := sh.srv.Handler //nil则利用默认的路由 if handler == nil { handler = DefaultServeMux } if req.RequestURI == "*" && req.Method == "OPTIONS" { handler = globalOptionsHandler{} } handler.ServeHTTP(rw, req) }
5 总结
路由部分,构建map来存储路由处理函数链接处理部分,构建一个tcp listener,然后accept,构建conn
然后通过conn,查找路由,找到处理函数,进行处理
龚浩华
qq 29185807 月牙寂-道长
2016年12月12日
相关文章推荐
- Golang中net/http包源码分析与解释
- TeamTalk源码分析之http_msg_server对外提供API
- TeamTalk源码分析之http_msg_server对外提供API
- TeamTalk源码分析之http_msg_server对外提供API
- BaseHTTPServer与CGIHTTPServer源码分析 - 技术手札
- golang net/http源码解读
- Go源码分析 net/http包分析:追溯到socket
- libevent源码分析:http-server例子
- HTTP SERVER[ListenAndServe函数]源码分析图
- Python标准库源码分析:BaseHTTPServer.py
- FileZilla Server源码分析(1)
- DC.Web.HttpCompress 压缩模块源码分析(二)
- IBM HTTP Server Plugin默认plugin-key.kdb 密钥数据库文件默认个人证书密码过期分析与解决方法
- FFServer源码分析
- 分布式文件系统KFS源码阅读与分析(二):MetaServer元数据持久化
- arcgis sample代码之SOE示例代码Length Calculator Server Object Extension的源码分析
- Asp.net MVC源码分析--Model Validation(Server端)实现(2)
- Asp.net MVC源码分析--Model Validation(Server端)实现(1)
- live555库的rtsp服务器源码分析总结,流程详解RTSPServer .
- 网络服务器开发框架spserver源码分析 (二)