Go实现web服务的流程

**

  1. 创建Listen Socket,监听指定的端口,等待客户端请求到来。
  2. Listen Socket接受客户端的请求,得到Client Socket,接下来通过Client Socket与客户端通信。
  3. 处理客户端请求,首先从Client Socket读取HTTP请求的协议头,如果是POST方法,还可能要读取客户端提交的数据,然后交给相应的handler处理请求,handler处理完,将数据通过Client Socket返回给客户端。

如何监听端口

通过ListenAndServe来监听,底层实现:初始化一个server对象,调用net.Listen(“tcp”,addr),也就是底层用TCP协议搭建了一个服务,监听设置的端口。然后调用srv.Serve(net.Listener)函数,这个函数处理接收客户端的请求信息。这个函数里起了一个for循环,通过Listener接收请求,创建conn,开一个goroutine,把请求的数据当作参数给conn去服务:go c.serve(),即每次请求都是在新的goroutine中去服务,利于高并发。

  1. // ListenAndServe always returns a non-nil error.
  2. func ListenAndServe(addr string, handler Handler) error {
  3. server := &Server{Addr: addr, Handler: handler}
  4. return server.ListenAndServe()
  5. }
  6. func (srv *Server) ListenAndServe() error {
  7. if srv.shuttingDown() {
  8. return ErrServerClosed
  9. }
  10. addr := srv.Addr
  11. if addr == "" {
  12. addr = ":http"
  13. }
  14. ln, err := net.Listen("tcp", addr)
  15. if err != nil {
  16. return err
  17. }
  18. return srv.Serve(ln)
  19. }

如何接收客户端的请求

  1. func (srv *Server) Serve(l net.Listener) error {
  2. if fn := testHookServerServe; fn != nil {
  3. fn(srv, l) // call hook with unwrapped listener
  4. }
  5. origListener := l
  6. l = &onceCloseListener{Listener: l}
  7. defer l.Close()
  8. if err := srv.setupHTTP2_Serve(); err != nil {
  9. return err
  10. }
  11. if !srv.trackListener(&l, true) {
  12. return ErrServerClosed
  13. }
  14. defer srv.trackListener(&l, false)
  15. baseCtx := context.Background()
  16. if srv.BaseContext != nil {
  17. baseCtx = srv.BaseContext(origListener)
  18. if baseCtx == nil {
  19. panic("BaseContext returned a nil context")
  20. }
  21. }
  22. var tempDelay time.Duration // how long to sleep on accept failure
  23. ctx := context.WithValue(baseCtx, ServerContextKey, srv)
  24. for {
  25. rw, err := l.Accept()
  26. if err != nil {
  27. select {
  28. case <-srv.getDoneChan():
  29. return ErrServerClosed
  30. default:
  31. }
  32. if ne, ok := err.(net.Error); ok && ne.Temporary() {
  33. if tempDelay == 0 {
  34. tempDelay = 5 * time.Millisecond
  35. } else {
  36. tempDelay *= 2
  37. }
  38. if max := 1 * time.Second; tempDelay > max {
  39. tempDelay = max
  40. }
  41. srv.logf("http: Accept error: %v; retrying in %v", err, tempDelay)
  42. time.Sleep(tempDelay)
  43. continue
  44. }
  45. return err
  46. }
  47. connCtx := ctx
  48. if cc := srv.ConnContext; cc != nil {
  49. connCtx = cc(connCtx, rw)
  50. if connCtx == nil {
  51. panic("ConnContext returned nil")
  52. }
  53. }
  54. tempDelay = 0
  55. c := srv.newConn(rw)
  56. c.setState(c.rwc, StateNew, runHooks) // before Serve can return
  57. go c.serve(connCtx)
  58. }
  59. }

关键代码

  1. c := srv.newConn(rw)
  2. c.setState(c.rwc, StateNew) // before Serve can return
  3. go c.serve()

newConn

  1. // Create new connection from rwc.
  2. func (srv *Server) newConn(rwc net.Conn) *conn {
  3. c := &conn{
  4. server: srv,
  5. rwc: rwc,
  6. }
  7. if debugServerConnections {
  8. c.rwc = newLoggingConn("server", c.rwc)
  9. }
  10. return c
  11. }

如何分配handler

conn先解析request:c.readRequest(),获取相应的handler:handler:=c.server.Handler,即ListenAndServe的第二个参数,因为值为nil,所以默认handler=DefaultServeMux。该变量是一个路由器,用来匹配url跳转到其相应的handle函数。其中http.HandleFunc(“/“,sayhelloName)即注册了请求“/”的路由规则,当uri为“/”时,路由跳转到函数sayhelloName。DefaultServeMux会调用ServeHTTP方法,这个方法内部调用sayhelloName本身,最后写入response的信息反馈给客户端。

c.serve()


  1. func (c *conn) serve() {
  2. ...
  3. for {
  4. w, err := c.readRequest()
  5. ...
  6. serverHandler{c.server}.ServeHTTP(w, w.req)
  7. ..
  8. }
  9. }

2.5.2. c.readRequest()

  1. // Serve a new connection.
  2. func (c *conn) serve() {
  3. ...
  4. for {
  5. w, err := c.readRequest()
  6. ...
  7. serverHandler{c.server}.ServeHTTP(w, w.req)
  8. ..
  9. }
  10. }
  11. 2.5.2. c.readRequest()
  12. // Read next request from connection.
  13. func (c *conn) readRequest() (w *response, err error) {
  14. if c.hijacked() {
  15. return nil, ErrHijacked
  16. }
  17. if d := c.server.ReadTimeout; d != 0 {
  18. c.rwc.SetReadDeadline(time.Now().Add(d))
  19. }
  20. if d := c.server.WriteTimeout; d != 0 {
  21. defer func() {
  22. c.rwc.SetWriteDeadline(time.Now().Add(d))
  23. }()
  24. }
  25. c.r.setReadLimit(c.server.initialReadLimitSize())
  26. c.mu.Lock() // while using bufr
  27. if c.lastMethod == "POST" {
  28. // RFC 2616 section 4.1 tolerance for old buggy clients.
  29. peek, _ := c.bufr.Peek(4) // ReadRequest will get err below
  30. c.bufr.Discard(numLeadingCRorLF(peek))
  31. }
  32. req, err := readRequest(c.bufr, keepHostHeader)
  33. c.mu.Unlock()
  34. if err != nil {
  35. if c.r.hitReadLimit() {
  36. return nil, errTooLarge
  37. }
  38. return nil, err
  39. }
  40. c.lastMethod = req.Method
  41. c.r.setInfiniteReadLimit()
  42. hosts, haveHost := req.Header["Host"]
  43. if req.ProtoAtLeast(1, 1) && (!haveHost || len(hosts) == 0) {
  44. return nil, badRequestError("missing required Host header")
  45. }
  46. if len(hosts) > 1 {
  47. return nil, badRequestError("too many Host headers")
  48. }
  49. if len(hosts) == 1 && !validHostHeader(hosts[0]) {
  50. return nil, badRequestError("malformed Host header")
  51. }
  52. for k, vv := range req.Header {
  53. if !validHeaderName(k) {
  54. return nil, badRequestError("invalid header name")
  55. }
  56. for _, v := range vv {
  57. if !validHeaderValue(v) {
  58. return nil, badRequestError("invalid header value")
  59. }
  60. }
  61. }
  62. delete(req.Header, "Host")
  63. req.RemoteAddr = c.remoteAddr
  64. req.TLS = c.tlsState
  65. if body, ok := req.Body.(*body); ok {
  66. body.doEarlyClose = true
  67. }
  68. w = &response{
  69. conn: c,
  70. req: req,
  71. reqBody: req.Body,
  72. handlerHeader: make(Header),
  73. contentLength: -1,
  74. }
  75. w.cw.res = w
  76. w.w = newBufioWriterSize(&w.cw, bufferBeforeChunkingSize)
  77. return w, nil
  78. }

ServeHTTP(w, w.req)

  1. func (sh serverHandler) ServeHTTP(rw ResponseWriter, req *Request) {
  2. handler := sh.srv.Handler
  3. if handler == nil {
  4. handler = DefaultServeMux
  5. }
  6. if req.RequestURI == "*" && req.Method == "OPTIONS" {
  7. handler = globalOptionsHandler{}
  8. }
  9. handler.ServeHTTP(rw, req)
  10. }

DefaultServeMux

  1. type ServeMux struct {
  2. mu sync.RWMutex
  3. m map[string]muxEntry
  4. hosts bool // whether any patterns contain hostnames
  5. }
  6. type muxEntry struct {
  7. explicit bool
  8. h Handler
  9. pattern string
  10. }
  11. // NewServeMux allocates and returns a new ServeMux.
  12. func NewServeMux() *ServeMux { return &ServeMux{m: make(map[string]muxEntry)} }
  13. // DefaultServeMux is the default ServeMux used by Serve.
  14. var DefaultServeMux = NewServeMux()

handler接口的定义

  1. type Handler interface {
  2. ServeHTTP(ResponseWriter, *Request)
  3. }

ServeMux.ServeHTTP

  1. // ServeHTTP dispatches the request to the handler whose
  2. // pattern most closely matches the request URL.
  3. func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) {
  4. if r.RequestURI == "*" {
  5. if r.ProtoAtLeast(1, 1) {
  6. w.Header().Set("Connection", "close")
  7. }
  8. w.WriteHeader(StatusBadRequest)
  9. return
  10. }
  11. h, _ := mux.Handler(r)
  12. h.ServeHTTP(w, r)
  13. }

mux.Handler(r)

  1. // Handler returns the handler to use for the given request,
  2. // consulting r.Method, r.Host, and r.URL.Path. It always returns
  3. // a non-nil handler. If the path is not in its canonical form, the
  4. // handler will be an internally-generated handler that redirects
  5. // to the canonical path.
  6. //
  7. // Handler also returns the registered pattern that matches the
  8. // request or, in the case of internally-generated redirects,
  9. // the pattern that will match after following the redirect.
  10. //
  11. // If there is no registered handler that applies to the request,
  12. // Handler returns a ``page not found'' handler and an empty pattern.
  13. func (mux *ServeMux) Handler(r *Request) (h Handler, pattern string) {
  14. if r.Method != "CONNECT" {
  15. if p := cleanPath(r.URL.Path); p != r.URL.Path {
  16. _, pattern = mux.handler(r.Host, p)
  17. url := *r.URL
  18. url.Path = p
  19. return RedirectHandler(url.String(), StatusMovedPermanently), pattern
  20. }
  21. }
  22. return mux.handler(r.Host, r.URL.Path)
  23. }
  24. // handler is the main implementation of Handler.
  25. // The path is known to be in canonical form, except for CONNECT methods.
  26. func (mux *ServeMux) handler(host, path string) (h Handler, pattern string) {
  27. mux.mu.RLock()
  28. defer mux.mu.RUnlock()
  29. // Host-specific pattern takes precedence over generic ones
  30. if mux.hosts {
  31. h, pattern = mux.match(host + path)
  32. }
  33. if h == nil {
  34. h, pattern = mux.match(path)
  35. }
  36. if h == nil {
  37. h, pattern = NotFoundHandler(), ""
  38. }
  39. return
  40. }

3. http的执行流程总结

  1. 首先调用Http.HandleFunc,按如下顺序执行:
    1. 调用了DefaultServerMux的HandleFunc。
    2. 调用了DefaultServerMux的Handle。
    3. 往DefaultServerMux的map[string] muxEntry中增加对应的handler和路由规则。
  2. 调用http.ListenAndServe(“:9090”,nil),按如下顺序执行:
    1. 实例化Server。
    2. 调用Server的ListenAndServe()。
    3. 调用net.Listen(“tcp”,addr)监听端口。
    4. 启动一个for循环,在循环体中Accept请求。
    5. 对每个请求实例化一个Conn,并且开启一个goroutine为这个请求进行服务go c.serve()。
    6. 读取每个请求的内容w,err:=c.readRequest()。
    7. 判断handler是否为空,如果没有设置handler,handler默认设置为DefaultServeMux。
    8. 调用handler的ServeHttp。
    9. 根据request选择handler,并且进入到这个handler的ServeHTTP, mux.handler(r).ServeHTTP(w,r)
    10. 选择handler
    11. 判断是否有路由能满足这个request(循环遍历ServeMux的muxEntry)。
    12. 如果有路由满足,调用这个路由handler的ServeHttp。
    13. 如果没有路由满足,调用NotFoundHandler的ServeHttp。