zoukankan      html  css  js  c++  java
  • Go源代码分析——http.ListenAndServe()是怎样工作的

    Go对webserver的编写提供了很好的支持,标准库中提供了net/http包来方便编写server。很多教程和书籍在讲到用Go编写webserver时都会直接教新手用http包写一个最简单的hello worldserver,样例几乎相同都会像这样:

    // 这就是用Go实现的一个最简短的hello worldserver.
    package main
    
    import "net/http"
    
    func main() {
    	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
    		w.Write([]byte(`hello world`))
    	})
    	http.ListenAndServe(":3000", nil) // <-今天讲的就是这个ListenAndServe是怎样工作的
    }
    

    能够看到。代码真的很简短,仅仅须要几行。我们今天要分析的是http.ListenAndServe(),看看这里面究竟都做了些什么。


    首先,http.ListenAndServe用到的全部依赖都在Go源代码中的/src/pkg/net/http/server.go文件里,打开它会发现这页代码很长,有2000+行,我们Ctrl+F直接找我们感兴趣的部分。发如今1770行左右的部分找到了http.ListenAndServe的定义:

    func ListenAndServe(addr string, handler Handler) error {
    	// 创建一个Server结构体,调用该结构体的ListenAndServer方法然后返回
    	server := &Server{Addr: addr, Handler: handler}
    	return server.ListenAndServe()
    }
    从这个函数中就能够看出,调用http.ListenAndServe之后真正起作用的是Server结构体LisntenAndServe方法。给http.ListenAndServe传递的參数仅仅是用来创建一个Server结构体实例,Server结构体的定义例如以下:

    type Server struct {
    	Addr           string        // server的IP地址和port信息
    	Handler        Handler       // 请求处理函数的路由复用器
    	ReadTimeout    time.Duration 
    	WriteTimeout   time.Duration
    	MaxHeaderBytes int       
    	TLSConfig      *tls.Config  
    	TLSNextProto map[string]func(*Server, *tls.Conn, Handler)
    	ConnState func(net.Conn, ConnState)
    	ErrorLog *log.Logger
    	disableKeepAlives int32 
    }
    假设我们不传详细的參数给http.ListenAndServe,那么它会自己主动以":http"(等价于":80")和DefaulServeMux作为參数来创建Server结构体实例。

    接下来继续看看Server.ListenAndServe里面都做了些什么,1675行左右能够找到定义:

    func (srv *Server) ListenAndServe() error {
    	addr := srv.Addr
    	if addr == "" {
    		addr = ":http"  // 假设不指定server地址信息。默认以":http"作为地址信息
    	}
    	ln, err := net.Listen("tcp", addr)    // 这里创建了一个TCP Listener,之后用于接收client的连接请求
    	if err != nil {
    		return err
    	}
    	return srv.Serve(tcpKeepAliveListener{ln.(*net.TCPListener)})  // 调用Server.Serve()函数并返回
    }
    能够看到。Server.ListenAndServe中创建了一个serverListener。然后在返回时把它传给了Server.Serve()方法并调用Server.Serve()。


    继续分析Server.Serve,定义的位置在1690行左右:

    func (srv *Server) Serve(l net.Listener) error {
    	defer l.Close()
    	var tempDelay time.Duration 
    	// 这个循环就是server的主循环了,通过传进来的listener接收来自client的请求并建立连接,
    	// 然后为每个连接创建routine运行c.serve()。这个c.serve就是详细的服务处理了
    	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() // <-这里为每个建立的连接创建routine之后进行服务
    	}
    }

    我们能够接着看看这个conn.serve()里面是怎么进行服务的。代码在1090行附近,仅仅看当中的主要部分:

    func (c *conn) serve() {
    	origConn := c.rwc // copy it before it's set nil on Close or Hijack
    
    	// 这里做了一些延迟释放和TLS相关的处理...
    	
    	// 前面的部分都能够忽略,这里才是基本的循环
    	for {
    		w, err := c.readRequest()  // 读取client的请求
    		// ...
    		serverHandler{c.server}.ServeHTTP(w, w.req) //这里对请求进行处理
    		if c.hijacked() {
    			return
    		}
    		w.finishRequest()
    		if w.closeAfterReply {
    			if w.requestBodyLimitHit {
    				c.closeWriteAndWait()
    			}
    			break
    		}
    		c.setState(c.rwc, StateIdle)
    	}
    }


    经过一路的分析,http.ListenAndServe工作的流程就几乎相同明晰了,我们能够总结成一张流程图:





    假设转载请注明出处:http://blog.csdn.net/gophers


  • 相关阅读:
    基于Metaweblog API 接口一键发布到国内外主流博客平台
    uva144 Student Grants
    Uva 10452
    Uva 439 Knight Moves
    Uva 352 The Seasonal War
    switch语句
    java——基础知识
    我的lua学习2
    codeforces 431 D. Random Task 组合数学
    codeforces 285 D. Permutation Sum 状压 dfs打表
  • 原文地址:https://www.cnblogs.com/yangykaifa/p/6719657.html
Copyright © 2011-2022 走看看