• Go 的 http 包的源码,通过代码我们可以看到整个的 http 处理过程


    func (srv *Server) Serve(l net.Listener) error {defer l.Close()
    var tempDelay time.Duration // how long to sleep on accept failure
    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
    }
    log.Printf("http: Accept error: %v; retrying in %v", e, tempDelay)
    time.Sleep(tempDelay)
    continue
    }
    return e
    }
    tempDelay = 0
    if srv.ReadTimeout != 0 {
    rw.SetReadDeadline(time.Now().Add(srv.ReadTimeout))
    }
    if srv.WriteTimeout != 0 {
    rw.SetWriteDeadline(time.Now().Add(srv.WriteTimeout))
    }
    c, err := srv.newConn(rw)
    if err != nil {
    continue
    }
    go c.serve()
    }
    panic("not reached")
    }
    监控之后如何接收客户端的请求呢?上面代码执行监控端口之后,调用了srv.Serve(net.Listener)函数,这个函数就是处理接收客户端的请求信息。这个函数里面起了一个 for{},首先通过 Listener 接收请求,其次创建一个 Conn,最后单独开了一个goroutine,把这个请求的数据当做参数扔给这个 conn 去服务:go c.serve()。这个就是高并发体现了,用户的每次请求都是在一个新的 goroutine 去服务,相互不影响。那么如何具体分配到相应的函数来处理请求呢?
     
    conn 首先会解析 request:c.readRequest(),然后获取相应的 handler:handler := c.server.Handler,也就是我们刚才在调用函数ListenAndServe 时候的第二个参数,我们前面例子传递的是 nil,也就是为空,那么默认获取 handler = DefaultServeMux,那么这个变量用来做什么的呢?对,这个变量就是一个路由器,它用来匹配 url 跳转到其相应的 handle 函数,那么这个我们有设置过吗?有,我们调用的代码里面第一句不是调用了 http.HandleFunc("/", sayhelloName)嘛。
     
    这个作用就是注册了请求/的路由规则,当请求 uri 为"/",路由就会转到函数 sayhelloName,DefaultServeMux会调用 ServeHTTP 方法,这个方法内部其实就是调用 sayhelloName 本身,最后通过写入response 的信息反馈到客户端。
     
    Go 的 http 有两个核心功能:Conn、ServeMux
    type Handler interface {
        ServeHTTP(ResponseWriter, *Request) // 路由实现器
    }
    Handler 是一个接口,但是前一小节中的 sayhelloName 函数并没有实现 ServeHTTP 这个接口,为什么能添加呢?原来在 http 包里面还定义了一个类型 HandlerFunc,我们定义的函 数 sayhelloName 就是这个 HandlerFunc 调用之后的结果,这个类型默认就实现了ServeHTTP 这个接口,即我们调用了 HandlerFunc(f),强制类型转换 f 成为 HandlerFunc 类型,这样 f 就拥有了 ServHTTP 方法。
    type HandlerFunc func(ResponseWriter, *Request)
    // ServeHTTP calls f(w, r)
    func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
        f(w, r)
    }
     
    按顺序做了几件事:
    1 调用了 DefaultServerMux 的 HandleFunc
    2 调用了 DefaultServerMux 的 Handle3 往 DefaultServeMux 的 map[string]muxEntry 中增加对应的 handler 和路由规则
    • 其次调用 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),handler 就设置为 DefaultServeMux
    8 调用 handler 的 ServeHttp
    9 在这个例子中,下面就进入到 DefaultServerMux.ServeHttp
    10 根据 request 选择 handler,并且进入到这个 handler 的 ServeHTTP
    mux.handler(r).ServeHTTP(w, r)
    11 选择 handler:
    A 判断是否有路由能满足这个 request(循环遍历 ServerMux 的 muxEntry)
    B 如果有路由满足,调用这个路由 handler 的 ServeHttp
    C 如果没有路由满足,调用 NotFoundHandler 的 ServeHttp
  • 相关阅读:
    CentOS 7,使用yum安装Nginx
    2019年6月Github最新开源java项目
    SQL Server清空数据库中ldf日志文件
    Spring Boot中使用 Thymeleaf
    Excel中使用Power Query获取网页json数据
    “工作做得越好,活越多,还不如偷懒?”这取决于你的目标
    Tomcat权威指南(第二版)下载pdf 高清完整中文版-百度云下载
    基于Xposed hook 实时监测微信消息
    Kotlin学习入门笔记
    批处理运行Vstest并生成HTML报告
  • 原文地址:https://www.cnblogs.com/setevn/p/11133234.html
Copyright © 2020-2023  润新知