开发者

Golang HTTP编程的源码解析详解

开发者 https://www.devze.com 2023-02-21 10:55 出处:网络 作者: Amos01
目录1、网络基础2、golang HTTP编程2.1 代码示例2.2 源码分析3. 总结1、网络基础 基本TCP客户-服务器程序Socket编程流程如如下图所示。
目录
  • 1、网络基础
  • 2、golang HTTP编程
    • 2.1 代码示例
    • 2.2 源码分析
  • 3. 总结

    1、网络基础

    基本TCP客户-服务器程序Socket编程流程如如下图所示。

    TCP服务器绑定到特定端口并阻塞监听客户端端开发者_自学开发连接,

    TCP客户端则通过IP+端口向服务器发起请求,客户-服务器建立连接之后就能开始进行数据传输。

    Golang HTTP编程的源码解析详解

    Golang的TCP编程也是基于上述流程的。

    2、Golang HTTP编程

    2.1 代码示例

    func timeHandler(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "%v", time.Now().Format(time.RFC3339))
    }
     
    func helloHandler(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "%v", "hello world.")
    }
     
    func main() {
        // 1. 新建路由解码器
        h := http.NewServeMux()
        // 2. 路由注册
        h.HandleFunc("/hello", helloHandler)
        h.HandleFunc("/time", timeHandler)
        // 3. 服务启动 阻塞监听
        http.ListenAndServe(":8000", h)
    }
    

    运行上述程序,在浏览器地址栏分别输入 http://localhost:8000/hello http://localhost:8000/time 结果分别如下图所示。

    Golang HTTP编程的源码解析详解

    Golang HTTP编程的源码解析详解

    2.2 源码分析

    分析从路由注册到响应用户请求的流程。

    2.2.1 新建解码器 h := http.NewServeMux()

    type ServeMux struct {
        mu    sync.RWMutex
        m     map[string]muxEntry
        es    []muxEntry // slice of entries sorted from longest to shortest.
        hosts bool       // whether any patterns contain hostnames
    }
    type muxEntry struct {
        h       Handler
        pattern string
    }
    // NewServeMux allocates and returns a new ServeMux.
    func NewServeMux() *ServeMux { return new(www.devze.comServeMux) }
    

    Handler是interface,定义如下

    type Handler interface {
        ServeHTTP(ResponseWriter, *Request)
    }
    

    ServeMux实现了Handler接口。

    2.2.2 路由注册 h.HandleFunc("/hello", helloHandler)

    // HandleFunc registers the handler function for the given pattern.
    func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
        ...
        mux.Handle(pattern, HandlerFunc(handler))
    }
     
    func (mux *ServeMux) Handle(pattern string, handler Handler) {
        ...
        e := muxEntry{h: handler, pattern: pattern}
        mux.m[pattern] = e
        if pattern[len(pattern)-1] == '/' {
            mux.es = appendSorted(mux.es, e)
        }
        ...
    }
    

    timeHandler和helloHandler函数被强制转换为type HandlerFunc func(ResponseWriter, *Request)类型,且实现了Handler接口。

    func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
        f(w, r)
    }
    

    mux.m建立了路由到处理函数timeHandler和helloHandler的映射。

    2.2.3 服务启动阻塞监听 http.ListenAndServe(":8000", h)

    包装Server结构体,HTTP使用TCP协议。

    func ListenAndServe(addr string, handler Handler) error {
        server := &Server{Addr: addr, Handler: handler}
        return server.ListenAndServe()
    }
    func (srv *Server) ListenAndServe() error {
        ...
        ln, err := net.Listen("tcp", addr)
        if err != nil {
            return err
        }
        return srv.Serve(ln)
    }
    

    net.Listen封装了Socket编程的socket,bind,listen的调用,极大的方便了使用者。

    阻塞监听请求,新建goroutine处理每个新请求。

    func (srv *Server) Serve(l net.Listener) error {
        ...
        for {
            rw, err := l.Accept()
            ...
            c := srv.newConn(rw)
            c.setState(c.rwc, StateNew, runHooks) // before Serve can return
            go c.serve(connCtx)
        }
    }
    // Serve a new connectandroidion.
    func (c *conn) serve(ctx context.Context) {
        ...
        serverHandler{c.server}.ServeHTTP(w, w.req)
        ...
    }
    func (sh servepythonrHandler) ServeHTTP(rw ResponseWriter, req *Request) {
        handler := sh.srv.Handler
        ...
        handler.ServeHTTP(rw, req)
    }
    

    通过前www.devze.com面的流程推导可知,hand编程客栈ler是http.ListenAndServe的第二个参数ServeMux

    // ServeHTTP dispatches the request to the handler whose
    // pattern most closely matches the request URL.
    func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) {
        ...
        h, _ := mux.Handler(r) // 通过路由获取处理函数
        h.ServeHTTP(w, r)
    }
    

    mux.Handler使用mux.m这个map通过请求URL找到对应处理函数的。

    h的实际类型为HandlerFunc,根据2.2.2会调用到具体函数timeHandler或者helloHandler。

    3. 总结

    golang对socket编程进行了封装,给HTTP编程带来了极大的便利。

    但是不支持以下特性

    1. 路由分组 对路由进行分组,可以方便分组鉴权

    2. 动态路由 如动态路由/user/:username/post/:postid不支持

    以上就是Golang HTTP编程的源码解析详解的详细内容,更多关于Golang HTTP编程的资料请关注我们其它相关文章!

    0

    精彩评论

    暂无评论...
    验证码 换一张
    取 消

    关注公众号