在上一篇里面我们通过:
func main() {
http.HandleFunc("/hello", func(w http.ResponseWriter, r *http.Request) {
io.WriteString(w, "hello")
})
http.ListenAndServe(":9010", nil)
}
分析了 http.handleFunc 的路由调用之间的关系。这次。我们分析一下 http.ListenAndServe():
http.ListenAndServe(addr string, handler Handler)
函数的内部实现:
func ListenAndServe(addr string, handler Handler) error {
server := &Server{Addr: addr, Handler: handler}
return server.ListenAndServe()
}
发现这个http.ListenAndServe 其实调用的是 Server.ListenAndServe。我们先来看看 Server的结构:
type Server struct {
Addr string // TCP address to listen on, ":http" if empty
Handler Handler //处理器,如果为空则使用 http.DefaultServeMux
ReadTimeout time.Duration
WriteTimeout time.Duration
....
}
看到这个Handler,再联系上次我们分析的http.HandleFunc。我们发现他们默认都使用了 http.DefaultServeMux 这个路由处理器。而在这个处理器里面 刚好保存了我们注册的一个路由。/hello。然后我们看看 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)})
}
在 server.ListenAndServe 里面注册了一个tcp的监听器,监听我们注册的网络端口。接着继续调用
server.Serve(l net.Listener) error
进行服务。
func (srv *Server) Serve(l net.Listener) error {
.......
for {
rw, e := l.Accept()
....
c := srv.newConn(rw)
c.setState(c.rwc, StateNew) // before Serve can return
go c.serve(ctx)
}
}
开启一个for循环,接受net.accept()。接着使用了 srv.newConn(net.conn) 把一个tcp的conn转换成一个http.server#conn:
func (srv *Server) newConn(rwc net.Conn) *conn {
c := &conn{
server: srv,
rwc: rwc,
}
....
return c
}
最后开启一个go协程对每个请求进行处理。
func (c *conn) serve(ctx context.Context) {
// 客户端主机ip
c.remoteAddr = c.rwc.RemoteAddr().String()
....
// HTTP/1.x from here on.
//读取请求的数据
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)
...
}
}
请求经过七倒八倒,最后进入了:
serverHandler{c.server}.ServeHTTP(w, w.req)
并且调用了它里面的ServerHandler.serveHTTP。果断点开这个函数,豁然开朗,原来是调用了最上层:
http.DefaultServeMux.Handle
不信看这里:
type serverHandler struct {
srv *Server
}
func (sh serverHandler) ServeHTTP(rw ResponseWriter, req *Request) {
//sh.srv.Handler =server.handler
handler := sh.srv.Handler
if handler == nil {
//我们最初传的参数就是 nil
handler = DefaultServeMux
}
if req.RequestURI == "*" && req.Method == "OPTIONS" {
handler = globalOptionsHandler{}
}
handler.ServeHTTP(rw, req)
}
所以啊,最后的处理是函数是 路由里面的 ServeMux.ServeHTTP,昨晚我们已经分析了ServeMux.ServeHTTP执行的是 我们自己传进去的函数。 服务器 开启以后一个请求 进来,首先调用的是 Server.ServeHTTP(rw ResponseWriter, req *Request).
func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) {
.....
h, _ := mux.Handler(r)
h.ServeHTTP(w, r)
}
上面的函数 再经过倒腾,最后转到这到ServeMux#handler函数里面:
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
}
在这个方法 里面就对 URL进行了匹配。匹配上就返回对应的URL的handle,否则就是 调用 NotFoundHandler。然后调用muxEntry.h,就是我们自定义处理的逻辑函数。
这样一个完整的 请求 http请求在golang里面的流通过程已经非常的清晰了是不是 ?
关注程序猿公众账号:
有疑问加站长微信联系(非本文作者)