dongmu5815 2018-01-04 14:13
浏览 21
已采纳

Web服务器代码流[关闭]

I am creating a simple web server using Go using net/HTTP package. The simple code is like this:

package main
import (
    "fmt"
    "net/http"
)
type hotdog int
func (m hotdog) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintln(w, "Any code you want in this func")
}
func main() {
    var d hotdog
    http.ListenAndServe(":8080", d)
}

So, I want to know what is happening under the hood? If I am not wrong

ListenAndServe() takes the address and handler and this function runs inside the library

func ListenAndServe(addr string, handler Handler) error {
    server := &Server{Addr: addr, Handler: handler}
    return server.ListenAndServe()
  } 

and after this function calls the 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)})
  }

Now the Serve Function is called. But I am not able to understand how this parameter (tcpKeepAliveListener{ln.(*net.TCPListener)}) is converted to (l net.Listener) in Serve Function

func (srv *Server) Serve(l net.Listener) error {
    defer l.Close()
    if fn := testHookServerServe; fn != nil {
        fn(srv, l)
    }
    var tempDelay time.Duration // how long to sleep on accept failure

    if err := srv.setupHTTP2_Serve(); err != nil {
        return err
    }

    srv.trackListener(l, true)
    defer srv.trackListener(l, false)

    baseCtx := context.Background() // base is always background, per Issue 16220
    ctx := context.WithValue(baseCtx, ServerContextKey, srv)
    for {
        rw, e := l.Accept()
        if e != nil {
            select {
            case <-srv.getDoneChan():
                return ErrServerClosed
            default:
            }
            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 := srv.newConn(rw)
        c.setState(c.rwc, StateNew) // before Serve can return
        go c.serve(ctx)
    }
  }

Where is the handler called?

  • 写回答

1条回答 默认 最新

  • dongshanxiao7328 2018-01-04 15:18
    关注

    As they've already commented, the net.Listener type is an interface, and tcpKeepAliveListener satisfies that interface, so the type is correct.

    Then, to answer your question about where is the Handler called, you need to go deeper in the code flow:

    The line go c.serve(ctx) from the last piece of code you posted, is calling conn.serve():

    // Serve a new connection.
    func (c *conn) serve(ctx context.Context) {
        c.remoteAddr = c.rwc.RemoteAddr().String()
        defer func() {
            if err := recover(); err != nil && err != ErrAbortHandler {
                const size = 64 << 10
                buf := make([]byte, size)
                buf = buf[:runtime.Stack(buf, false)]
                c.server.logf("http: panic serving %v: %v
    %s", c.remoteAddr, err, buf)
            }
            if !c.hijacked() {
                c.close()
                c.setState(c.rwc, StateClosed)
            }
        }()
    
        if tlsConn, ok := c.rwc.(*tls.Conn); ok {
            if d := c.server.ReadTimeout; d != 0 {
                c.rwc.SetReadDeadline(time.Now().Add(d))
            }
            if d := c.server.WriteTimeout; d != 0 {
                c.rwc.SetWriteDeadline(time.Now().Add(d))
            }
            if err := tlsConn.Handshake(); err != nil {
                c.server.logf("http: TLS handshake error from %s: %v", c.rwc.RemoteAddr(), err)
                return
            }
            c.tlsState = new(tls.ConnectionState)
            *c.tlsState = tlsConn.ConnectionState()
            if proto := c.tlsState.NegotiatedProtocol; validNPN(proto) {
                if fn := c.server.TLSNextProto[proto]; fn != nil {
                    h := initNPNRequest{tlsConn, serverHandler{c.server}}
                    fn(c.server, tlsConn, h)
                }
                return
            }
        }
    
        // HTTP/1.x from here on.
    
        ctx, cancelCtx := context.WithCancel(ctx)
        c.cancelCtx = cancelCtx
        defer cancelCtx()
    
        c.r = &connReader{conn: c}
        c.bufr = newBufioReader(c.r)
        c.bufw = newBufioWriterSize(checkConnErrorWriter{c}, 4<<10)
    
        for {
            w, err := c.readRequest(ctx)
            if c.r.remain != c.server.initialReadLimitSize() {
                // If we read any bytes off the wire, we're active.
                c.setState(c.rwc, StateActive)
            }
            if err != nil {
                const errorHeaders = "
    Content-Type: text/plain; charset=utf-8
    Connection: close
    
    "
    
                if err == errTooLarge {
                    // 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.
                    const publicErr = "431 Request Header Fields Too Large"
                    fmt.Fprintf(c.rwc, "HTTP/1.1 "+publicErr+errorHeaders+publicErr)
                    c.closeWriteAndWait()
                    return
                }
                if isCommonNetReadError(err) {
                    return // don't reply
                }
    
                publicErr := "400 Bad Request"
                if v, ok := err.(badRequestError); ok {
                    publicErr = publicErr + ": " + string(v)
                }
    
                fmt.Fprintf(c.rwc, "HTTP/1.1 "+publicErr+errorHeaders+publicErr)
                return
            }
    
            // Expect 100 Continue support
            req := w.req
            if req.expectsContinue() {
                if req.ProtoAtLeast(1, 1) && req.ContentLength != 0 {
                    // Wrap the Body reader with one that replies on the connection
                    req.Body = &expectContinueReader{readCloser: req.Body, resp: w}
                }
            } else if req.Header.get("Expect") != "" {
                w.sendExpectationFailed()
                return
            }
    
            c.curReq.Store(w)
    
            if requestBodyRemains(req.Body) {
                registerOnHitEOF(req.Body, w.conn.r.startBackgroundRead)
            } else {
                if w.conn.bufr.Buffered() > 0 {
                    w.conn.r.closeNotifyFromPipelinedRequest()
                }
                w.conn.r.startBackgroundRead()
            }
    
            // 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.
            // But we're not going to implement HTTP pipelining because it
            // was never deployed in the wild and the answer is HTTP/2.
            serverHandler{c.server}.ServeHTTP(w, w.req)
            w.cancelCtx()
            if c.hijacked() {
                return
            }
            w.finishRequest()
            if !w.shouldReuseConnection() {
                if w.requestBodyLimitHit || w.closedRequestBodyEarly() {
                    c.closeWriteAndWait()
                }
                return
            }
            c.setState(c.rwc, StateIdle)
            c.curReq.Store((*response)(nil))
    
            if !w.conn.server.doKeepAlives() {
                // We're in shutdown mode. We might've replied
                // to the user without "Connection: close" and
                // they might think they can send another
                // request, but such is life with HTTP/1.1.
                return
            }
    
            if d := c.server.idleTimeout(); d != 0 {
                c.rwc.SetReadDeadline(time.Now().Add(d))
                if _, err := c.bufr.Peek(4); err != nil {
                    return
                }
            }
            c.rwc.SetReadDeadline(time.Time{})
        }
    }
    

    and there, it calls serverHandler{c.server}.ServeHTTP(w, w.req):

    // serverHandler delegates to either the server's Handler or
    // DefaultServeMux and also handles "OPTIONS *" requests.
    type serverHandler struct {
        srv *Server
    }
    
    func (sh serverHandler) ServeHTTP(rw ResponseWriter, req *Request) {
        handler := sh.srv.Handler
        if handler == nil {
            handler = DefaultServeMux
        }
        if req.RequestURI == "*" && req.Method == "OPTIONS" {
            handler = globalOptionsHandler{}
        }
        handler.ServeHTTP(rw, req)
    }
    

    which is the function wrapper that then calls ServeHTTP for the corresponding handler set before:

    func (sh serverHandler) ServeHTTP(rw ResponseWriter, req *Request) {
        handler := sh.srv.Handler
        if handler == nil {
            handler = DefaultServeMux
        }
        if req.RequestURI == "*" && req.Method == "OPTIONS" {
            handler = globalOptionsHandler{}
        }
        handler.ServeHTTP(rw, req)
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 抖音咸鱼付款链接转码支付宝
  • ¥15 ubuntu22.04上安装ursim-3.15.8.106339遇到的问题
  • ¥15 求螺旋焊缝的图像处理
  • ¥15 blast算法(相关搜索:数据库)
  • ¥15 请问有人会紧聚焦相关的matlab知识嘛?
  • ¥15 网络通信安全解决方案
  • ¥50 yalmip+Gurobi
  • ¥20 win10修改放大文本以及缩放与布局后蓝屏无法正常进入桌面
  • ¥15 itunes恢复数据最后一步发生错误
  • ¥15 关于#windows#的问题:2024年5月15日的win11更新后资源管理器没有地址栏了顶部的地址栏和文件搜索都消失了