go语言http server解析之一

go server

go语言http server解析之一_第1张图片
图片模仿build web application with golang,学习画图技巧。

通过学习发现go写http server主要有以下两种方式,本文是分析beego中的httpServer和graceServer的基础前提。通过分析源码,和unix中开发server中的方式(socket,bind,listen,accetp)串连起来,而不仅仅是go给我们提供好的几个api。

方式1:ServeHTTP方式

package main

import (
    "log"
    "net/http"
)

type sayHandler struct {
}

func (h *sayHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("hello"))

}

func main() {
    log.Fatal(http.ListenAndServe(":8080", new(sayHandler)))
}

code-1-1

方式2:handleFunc方式

// Package main provides ...
package main

import (
    "log"
    "net/http"
)

func say(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("hello world"))
}

func main() {
    http.HandleFunc("/hello", say)
    log.Fatal(http.ListenAndServe(":8080", nil))
}

code-1-2

源码解析

先分析code-1-1中的代码,从ListenAndServe开始

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

code-1-3
看下Server

type Server struct {
    Addr    string  
    Handler Handler 
    ...
}

code-1-4
继续看下Handler

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

code-1-5
这里我们看到ListenAndServe第二个参数只要实现code-1-5中的接口就可以了。
我们回到code-1-3中继续分析。

func (srv *Server) ListenAndServe() error {
    ....
    ln, err := net.Listen("tcp", addr)
    ....
    return srv.Serve(ln)
}

code-1-6
这里调用了Listen,继续下

 func (srv *Server) Serve(l net.Listener) error {
    ....
    for {
        rw, e := l.Accept()
        ...
        c := srv.newConn(rw)
        c.setState(c.rwc, StateNew)
        go c.serve(ctx)
    }
}

code-1-7
这里调用了Accetp,得到了socket连接。
看一下newConn,这个主要是封装下,可以读取server的方法。go c.serve(ctx)可以每个连接一个协程处理。

func (srv *Server) newConn(rwc net.Conn) *conn {
    c := &conn{
        server: srv,
        rwc:    rwc,
    }
    ...
    return c
}

code-1-8

// Serve a new connection.
func (c *conn) serve(ctx context.Context) {
    ...
    for {
        w, err := c.readRequest(ctx)
        
        ...
    
        serverHandler{c.server}.ServeHTTP(w, w.req)
        ...
}

code-1-9

serverHandler{c.server}.ServeHTTP(w, w.req)会调用ServeHTTP方法。如果调用时传了Handler,则调用Handler的Serve。到现在我们回答了code-1-1中的问题了。

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)
}

code-1-10

code-1-2中的代码使用的是DefaultServeMux,我们下篇文章分析。

参考链接

http-servers
function handler
build-web-application-with-golang

你可能感兴趣的:(golang,源码分析,server)