golang-net/http源码分析之http server

本文csdn博客链接:http://blog.csdn.net/screscent/article/details/53583764
本文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

创建了一个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
		}

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日

qq 29185807

如果你觉得本文对你有帮助,可以转到你的朋友圈,让更多人一起学习。

第一时间获取文章,可以关注本人公众号:月牙寂道长,也可以扫码关注

在这里插入图片描述

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值