Golang中net/http包源码分析与解释

来源:互联网 发布:淘宝海关拍卖网 编辑:程序博客网 时间:2024/06/06 05:16

Golang中net/http包源码分析与解释

关于Golang语言的源码,我一直是使用LiteIDE中自带的源码阅读功能来解读的。这次对于net/http包的源码阅读与分析也是通过LiteIDE软件来完成的。
打开net/http包的相关源码,可以看出Golang对于http相关的操作有很多很完善的源码支持。比如对于server、client、transfer等等的操作。

由于源码数量和功能很多,所以下面就以一个简单的web服务器来简单解析一下server中的相关函数和操作对应的源码。

一个简单的Web Server

package mainimport (    "fmt"    "net/http"    "log")func main() {    http.HandleFunc("/", sayhelloName)       //设置访问的路由    err := http.ListenAndServe(":9090", nil) //设置监听的端口    if err != nil {        log.Fatal("ListenAndServe: ", err)    }}

对于它的实现,我们可以看到它使用了net/http包中的HandleFunc()函数以及ListenAndServe()函数,下面我们来分别解析一下这两个函数。

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中的函数,接下来看看DefaultServeMux.HandleFunc函数的实现:

// NewServeMux allocates and returns a new ServeMux.var DefaultServeMux = NewServeMux()func NewServeMux() *ServeMux { return &ServeMux{m: make(map[string]muxEntry)} }type ServeMux struct {    mu    sync.RWMutex                   //一个读写锁    m     map[string]muxEntry            //一个path(patterns)的映射map    hosts bool                          // whether any patterns contain hostnames}

再追溯到mux与ServeMux:

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}func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) {    if r.RequestURI == "*" {        if r.ProtoAtLeast(1, 1) {                                             w.Header().Set("Connection", "close")        }        w.WriteHeader(StatusBadRequest)        return    }    h, _ := mux.Handler(r)    h.ServeHTTP(w, r)}func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {    mux.Handle(pattern, HandlerFunc(handler))}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)    }    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, "/"):]        }        mux.m[pattern[0:n-1]] = muxEntry{h: RedirectHandler(path, StatusMovedPermanently), pattern: pattern}    }}

这样就完成了HandleFunc的实现和执行。
可见通过添加路由,Handler处理的入口就是serverHandler{c.server}.ServeHTTP(w, w.req),最终到HandleFunc的执行。

http.ListenAndServe函数源代码解析

func ListenAndServe(addr string, handler Handler) error {    server := &Server{Addr: addr, Handler: handler}    return server.ListenAndServe()}

可看出该函数调用了server中的函数,接下来看看server.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)})}

可见,该函数中又调用到了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.func (srv *Server) Serve(l net.Listener) error {    defer l.Close()    var tempDelay time.Duration // how long to sleep on accept failure    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, err := srv.newConn(rw)        if err != nil {            continue        }        c.setState(c.rwc, StateNew) // before Serve can return        go c.serve()    }}

可见,server为每一个请求建立一个连接,同时进行逻辑的处理。这样就完成了ListenAndServe的实现和执行。

总结

http.HandleFunc:
调用http.HandleFunc->调用DefaultServerMux.HandleFunc->调用DefaultServerMux的Handle

http.ListenAndServe:
实例化Server->调用Server.ListenAndServe()->为每一个请求建立一个连接,同时进行逻辑的处理,进行go c.serve(),读取每个请求的内容->调用handler.ServeHttp->根据request选择handler->mux.handler(r).ServeHTTP(w,r),选择handler。

根据对源码的分析,对整个函数的执行过程和方法有了更深刻的理解,不由得说,分析源码是学习一门语言最好的方式。对于net/http包的学习让我对 http 协议的工作原理和实现技术有了初步了解。

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 工行证书介质已被锁定怎么办 学历认证是假的怎么办 怕被公司查学历怎么办 淘宝玩具没有怎么办3c 家庭遭遇小三我该怎么办 老公出轨把小三带回家了怎么办 小三怀孕了怎么办准生证 小三怀孕了起诉怎么办 不知情做了小三怎么办 发现自己被三了怎么办 被扇巴掌脸肿了怎么办 分到上海市金鼎学校怎么办 被列入维稳对象怎么办? 资金涉及诈骗案冻结了怎么办 小米浏览器浏览记录找不到了怎么办 米聊账号封了怎么办 管家婆创业版管理员忘记密码怎么办 手机不记得密码了怎么办 手机不记得开锁密码怎么办 oppo手机不记得密码怎么办 电脑密码不记得了怎么办 vivo手机不记得密码了怎么办 运管把车扣了怎么办 大学通选课挂科怎么办 通识必修课挂了怎么办 我想开3d艺术馆怎么办 档案回原籍报到证怎么办 服刑的人孩子上学怎么办 长沙终身教育网用户名忘记了怎么办 乡下卖服装没生意怎么办 没能力没学历该怎么办 没有学历的我该怎么办 补过的牙掉了怎么办 法院判完被告不给钱怎么办 b证到期未继续教育怎么办 宝宝上幼儿园中午要用尿不湿怎么办 嫁到北京农村怎么办居住证 2020年没脱贫的农民怎么办 2020年农民的土地怎么办 车停在停车场被划怎么办 专升本差两分怎么办