zoukankan      html  css  js  c++  java
  • Golang Http Server源码阅读

    建议看这篇文章前先看一下net/http文档 http://golang.org/pkg/net/http/

    net.http包里面有很多文件,都是和http协议相关的,比如设置cookie,header等。其中最重要的一个文件就是server.go了,这里我们阅读的就是这个文件。

    几个重要概念

    ResponseWriter: 生成Response的接口

    Handler: 处理请求和生成返回的接口

    ServeMux: 路由,后面会说到ServeMux也是一种Handler

    Conn : 网络连接

    具体分析

    几个接口:

    Handler

    实现了handler接口的对象就意味着往server端添加了处理请求的逻辑。

    type Handler interface {
    
        ServeHTTP(ResponseWriter, *Request)  // 具体的逻辑函数
    
    }
    

      下面是三个接口(ResponseWriter, Flusher, Hijacker):

    ResponseWriter, Flusher, Hijacker

    // ResponseWriter的作用是被Handler调用来组装返回的Response的
    type ResponseWriter interface {
        // 这个方法返回Response返回的Header供读写
        Header() Header
     
        // 这个方法写Response的Body
        Write([]byte) (int, error)
         
        // 这个方法根据HTTP State Code来写Response的Header
        WriteHeader(int)
    }
     
    // Flusher的作用是被Handler调用来将写缓存中的数据推给客户端
    type Flusher interface {
        // 这个方法将写缓存中数据推送给客户端
        Flush()
    }
     
    // Hijacker的作用是被Handler调用来关闭连接的
    type Hijacker interface {
        // 这个方法让调用者主动管理连接
        Hijack() (net.Conn, *bufio.ReadWriter, error)
     
    }
    

      

    response

    实现这三个接口的结构是response(这个结构是http包私有的,在文档中并没有显示,需要去看源码)

    // response包含了所有server端的http返回信息
    type response struct {
        conn          *conn         // 保存此次HTTP连接的信息
        req           *Request // 对应请求信息
        chunking      bool     // 是否使用chunk
        wroteHeader   bool     // header是否已经执行过写操作
        wroteContinue bool     // 100 Continue response was written
        header        Header   // 返回的http的Header
        written       int64    // Body的字节数
        contentLength int64    // Content长度
        status        int      // HTTP状态
        needSniff     bool     // 是否需要使用sniff。(当没有设置Content-Type的时候,开启sniff能根据HTTP body来确定Content-Type)
         
        closeAfterReply bool     //是否保持长链接。如果客户端发送的请求中connection有keep-alive,这个字段就设置为false。
     
        requestBodyLimitHit bool //是否requestBody太大了(当requestBody太大的时候,response是会返回411状态的,并把连接关闭)
     
    }
    

      在response中是可以看到

    func (w *response) Header() Header
    func (w *response) WriteHeader(code int)
    func (w *response) Write(data []byte) (n int, err error)
    func (w *response) Flush()
    func (w *response) Hijack() (rwc net.Conn, buf *bufio.ReadWriter, err error)
    

      

    这么几个方法。所以说response实现了ResponseWriter,Flusher,Hijacker这三个接口

    HandlerFunc

    handlerFunc是经常使用到的一个type

    type HandlerFunc func(ResponseWriter, *Request)
     
    // ServeHTTP calls f(w, r).
    func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
        f(w, r)
    }
    

     

    这里需要多回味一下了,这个HandlerFunc定义和ServeHTTP合起来是说明了什么?说明HandlerFunc的所有实例是实现了ServeHttp方法的。另,实现了ServeHttp方法就是什么?实现了接口Handler!

    所以你以后会看到很多这样的句子:

     

    func AdminHandler(w ResponseWriter, r *Request) {
        ...
    }
    handler := HandlerFunc(AdminHandler)
    handler.ServeHttp(w,r)
    

      

    请不要讶异,你明明没有写ServeHttp,怎么能调用呢? 实际上调用ServeHttp就是调用AdminHandler。

    HandlerFunc(AdminHandler)是一个转换而非一个函数调用,因为http.HandlerFunc是一个类型。HandlerFunc显示了在Go语言接口机制中一些不同寻常的特点。这是一个有实现了接口http.Handler方法的函数类型。ServeHTTP方法的行为调用了它本身的函数。因此HandlerFunc是一个让函数值满足一个接口的适配器(此处是http.Handler接口适配器,因为serverHTTP实现了Handler接口),这里函数和这个接口仅有的方法有相同的函数签名。实际上,这个技巧让一个单一的类型例如MyHandler以多种方式满足http.Handler接口。

    附带上一个play.google写的一个小例子

    http://play.golang.org/p/nSt_wcjc2u

    有兴趣继续研究的同学可以继续试验下去

    下面接着看Server.go

    ServerMux结构

    它就是http包中的路由规则器。你可以在ServerMux中注册你的路由规则,当有请求到来的时候,根据这些路由规则来判断将请求分发到哪个处理器(Handler)。

    它的结构如下:

    type ServeMux struct {
        mu sync.RWMutex   //锁,由于请求设计到并发处理,因此这里需要一个锁机制
        m  map[string]muxEntry  // 路由规则,一个string对应一个mux实体,这里的string就是我注册的路由表达式
    }
    

      下面看一下muxEntry

    type muxEntry struct {
        explicit bool   // 是否精确匹配
        h        Handler // 这个路由表达式对应哪个handler
    }
    

      

    看到这两个结构就应该对请求是如何路由的有思路了:

    当一个请求request进来的时候,server会依次根据ServeMux.m中的string(路由表达式)来一个一个匹配,如果找到了可以匹配的muxEntry,就取出muxEntry.h,这是个handler,调用handler中的ServeHTTP(ResponseWriter, *Request)来组装Response,并返回。

    ServeMux定义的方法有:

    func (mux *ServeMux) match(path string) Handler   //根据path获取Handler
    func (mux *ServeMux) handler(r *Request) Handler  //根据Request获取Handler,内部实现调用match
    func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) //!!这个说明,ServeHttp也实现了Handler接口,它实际上也是一个Handler!内部实现调用handler
    func (mux *ServeMux) Handle(pattern string, handler Handler) //注册handler方法
     
    func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request))  //注册handler方法(直接使用func注册)
    

      

    在godoc文档中经常见到的DefaultServeMux是http默认使用的ServeMux

    var DefaultServeMux = NewServeMux()

    如果我们没有自定义ServeMux,系统默认使用这个ServeMux。

    换句话说,http包外层(非ServeMux)中提供的几个方法:

    func Handle(pattern string, handler Handler) { DefaultServeMux.Handle(pattern, handler) }
    func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
        DefaultServeMux.HandleFunc(pattern, handler)
    }
    

      

    实际上就是调用ServeMux结构内部对应的方法。

    Server

    下面还剩下一个Server结构

    type Server struct {
        Addr           string        // 监听的地址和端口
        Handler        Handler       // 所有请求需要调用的Handler(实际上这里说是ServeMux更确切)如果为空则设置为DefaultServeMux
        ReadTimeout    time.Duration // 读的最大Timeout时间
        WriteTimeout   time.Duration // 写的最大Timeout时间
        MaxHeaderBytes int           // 请求头的最大长度
        TLSConfig      *tls.Config   // 配置TLS
    }
    

      Server提供的方法有:

    func (srv *Server) Serve(l net.Listener) error   //对某个端口进行监听,里面就是调用for进行accept的处理了
    func (srv *Server) ListenAndServe() error  //开启http server服务,内部调用Serve
    func (srv *Server) ListenAndServeTLS(certFile, keyFile string) error //开启https server服务,内部调用Serve
    

      当然Http包也直接提供了方法供外部使用,实际上内部就是实例化一个Server,然后调用ListenAndServe方法

    func ListenAndServe(addr string, handler Handler) error   //开启Http服务
    func ListenAndServeTLS(addr string, certFile string, keyFile string, handler Handler) error //开启HTTPs服务
    

      

    参考:http://www.cnblogs.com/yjf512/archive/2012/08/22/2650873.html

  • 相关阅读:
    https://wuzhuti.cn/2175.html
    http://www.importnew.com/10937.html
    http://blog.sina.com.cn/s/blog_62e1faba010147k4.html
    http://www.cnblogs.com/langtianya/archive/2013/02/01/2889682.html
    http://www.binghe.org/2010/03/use-httpsurlconnection-in-java/
    http://risheng.iteye.com/blog/1876573
    http://blog.csdn.net/rongyongfeikai2/article/details/41659353
    http://zhidao.baidu.com/link?url=inouJq69pK4PVM2L26fvnxXfRKhJ1uKmttgVqIEqld14SEUa8JzXZfRYHS3qdltqMXBgEQycFsF8AI9DlSoH4_
    http://blog.csdn.net/szwangdf/article/details/23432783
    win8连接蓝牙听歌
  • 原文地址:https://www.cnblogs.com/DaBing0806/p/6957559.html
Copyright © 2011-2022 走看看