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 协议的工作原理和实现技术有了初步了解。
- Golang中net/http包源码分析与解释
- Golang中gzip过滤器的源码分析与解释
- golang中net/http包用法
- golang中net/http包用法
- golang-net/http源码分析之http server
- golang net/http包使用
- golang net/http源码解读
- golang中net包用法
- Go源码分析 net/http包分析:追溯到socket
- Golang学习之net/http包
- 简单阅读golang的net/http包和Negroni的源码
- golang中http包获取表单
- golang http server 源码解析与说明
- golang中net包用法(二)--IP
- golang中net包用法(一)
- golang中net/mail包用法
- golang 建立web服务器 http包源码详解
- 【golang 源码分析】内存分配与管理
- easyui datagrid 获得编辑后的数据
- Easyrecyclerview 使用体验
- html学习记录1
- 实验四-Linux系统管理
- mysql集群的使用与简单测试
- Golang中net/http包源码分析与解释
- 使用百度地图API将输入地址转化成坐标
- 独热编码通俗理解和实例
- compileSdkVersion 'android-24' requires JDK 1.8 or later to compile
- 在Pytorch中实现im2col操作 Implementing im2col in Pytorch
- 测试
- linux配置samba
- OpenGL之gluPerspective浅析
- tomcat版本打印console问题引起的锁问题