比如我们经常会有这样的代码开始一个网络端口监听:
err := http.ListenAndServe(listenAddr, nil)
http包中这个函数的实现是:
func ListenAndServe(addr string, handler Handler) error
:= &Server{Addr: addr, Handler: handler}
return
}
server.ListenAndServe() 函数的实现如下:
func (srv *Server) ListenAndServe() error
:=
if addr == ""
":http"
}
:= net.Listen("tcp", addr)
if e != nil
return
}
return
}
srv.Serve( 函数的实现如下,注意看到有网络连接产生后 c, err := srv.newConn(rw) ,我们开了一个协程。
func (srv *Server) Serve(l net.Listener) error
defer
var tempDelay time.Duration // how long to sleep on accept failure
for
:=
if e != nil
if ne, ok := e.(net.Error); ok &&
if tempDelay == 0
5 *
else
*= 2
}
if max := 1 *
tempDelay = max
}
"http: Accept error: %v; retrying in %v", e, tempDelay)
time.Sleep(tempDelay)
continue
}
return
}
0
if srv.ReadTimeout != 0
rw.SetReadDeadline(time.Now().Add(srv.ReadTimeout))
}
if srv.WriteTimeout != 0
rw.SetWriteDeadline(time.Now().Add(srv.WriteTimeout))
}
:=
if err != nil
continue
}
go
}
panic("not reached")
}
从上面可以看到,每个客户端请求连接,都是开始了一个协程。
每次请求的实体类包含的信息如下:
type conn struct {
remoteAddr string // network address of remote side
server *Server // the Server on which the connection arrived
// i/o connection
*io.LimitedReader // io.LimitReader(rwc)
buf *bufio.ReadWriter // buffered(lr,rwc), reading from bufio->limitReader->rwc
hijacked bool // connection has been hijacked by handler
*tls.ConnectionState // or nil when not using TLS
byte
}
c.serve( 方法包含整个连接从打开到关闭的整个生命周期,即,一个连接是一个协程。
// Serve a new connection.
func (c *conn) serve() {
defer func() {
:= recover()
if err == nil
return
}
var
&buf, "http: panic serving %v: %v\n", c.remoteAddr, err)
buf.Write(debug.Stack())
log.Print(buf.String())
if c.rwc !=nil { // may be nil if connection hijacked
c.rwc.Close()
}
}()
if tlsConn, ok := c.rwc.(*tls.Conn); ok {
if err := tlsConn.Handshake(); err != nil
close()
return
}
new(tls.ConnectionState)
*c.tlsState = tlsConn.ConnectionState()
}
for
:=
if err != nil
:= "400 Bad Request"
if err ==
// Their HTTP client may or may not be
// able to read this if we're
// responding to them and hanging up
// while they're still writing their
// request. Undefined behavior.
msg = "413 Request Entity Too Large"
else if err ==
break // Don't reply
else if neterr, ok := err.(net.Error); ok &&
break // Don't reply
}
"HTTP/1.1 %s\r\n\r\n", msg)
break
}
// Expect 100 Continue support
:=
if
if req.ProtoAtLeast(1, 1) {
// Wrap the Body reader with one that replies on the connection
&expectContinueReader{readCloser: req.Body, resp: w}
}
if req.ContentLength == 0
"Connection", "close")
w.WriteHeader(StatusBadRequest)
w.finishRequest()
break
}
"Expect")
else if req.Header.Get("Expect") != ""
// TODO(bradfitz): let ServeHTTP handlers handle
// requests with non-standard expectation[s]? Seems
// theoretical at best, and doesn't fit into the
// current ServeHTTP model anyway. We'd need to
// make the ResponseWriter an optional
// "ExpectReplier" interface or something.
//
// For now we'll just obey RFC 2616 14.20 which says
// "If a server receives a request containing an
// Expect field that includes an expectation-
// extension that it does not support, it MUST
// respond with a 417 (Expectation Failed) status."
"Connection", "close")
w.WriteHeader(StatusExpectationFailed)
w.finishRequest()
break
}
:=
if handler == nil
handler = DefaultServeMux
}
// HTTP cannot have multiple simultaneous active requests.[*]
// Until the server replies to this request, it can't read another,
// so we might as well run the handler in this goroutine.
// [*] Not strictly true: HTTP pipelining. We could let them all process
// in parallel even if their responses need to be serialized.
handler.ServeHTTP(w, w.req)
if
return
}
w.finishRequest()
if
break
}
}
close()
}