您的位置:首页 > 理论基础 > 计算机网络

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

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日

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  源码 golang http