Go实现web服务的流程
**
- 创建Listen Socket,监听指定的端口,等待客户端请求到来。
- Listen Socket接受客户端的请求,得到Client Socket,接下来通过Client Socket与客户端通信。
- 处理客户端请求,首先从Client Socket读取HTTP请求的协议头,如果是POST方法,还可能要读取客户端提交的数据,然后交给相应的handler处理请求,handler处理完,将数据通过Client Socket返回给客户端。
如何监听端口
通过ListenAndServe来监听,底层实现:初始化一个server对象,调用net.Listen(“tcp”,addr),也就是底层用TCP协议搭建了一个服务,监听设置的端口。然后调用srv.Serve(net.Listener)函数,这个函数处理接收客户端的请求信息。这个函数里起了一个for循环,通过Listener接收请求,创建conn,开一个goroutine,把请求的数据当作参数给conn去服务:go c.serve(),即每次请求都是在新的goroutine中去服务,利于高并发。
// ListenAndServe always returns a non-nil error.
func ListenAndServe(addr string, handler Handler) error {
server := &Server{Addr: addr, Handler: handler}
return server.ListenAndServe()
}
func (srv *Server) ListenAndServe() error {
if srv.shuttingDown() {
return ErrServerClosed
}
addr := srv.Addr
if addr == "" {
addr = ":http"
}
ln, err := net.Listen("tcp", addr)
if err != nil {
return err
}
return srv.Serve(ln)
}
如何接收客户端的请求
func (srv *Server) Serve(l net.Listener) error {
if fn := testHookServerServe; fn != nil {
fn(srv, l) // call hook with unwrapped listener
}
origListener := l
l = &onceCloseListener{Listener: l}
defer l.Close()
if err := srv.setupHTTP2_Serve(); err != nil {
return err
}
if !srv.trackListener(&l, true) {
return ErrServerClosed
}
defer srv.trackListener(&l, false)
baseCtx := context.Background()
if srv.BaseContext != nil {
baseCtx = srv.BaseContext(origListener)
if baseCtx == nil {
panic("BaseContext returned a nil context")
}
}
var tempDelay time.Duration // how long to sleep on accept failure
ctx := context.WithValue(baseCtx, ServerContextKey, srv)
for {
rw, err := l.Accept()
if err != nil {
select {
case <-srv.getDoneChan():
return ErrServerClosed
default:
}
if ne, ok := err.(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", err, tempDelay)
time.Sleep(tempDelay)
continue
}
return err
}
connCtx := ctx
if cc := srv.ConnContext; cc != nil {
connCtx = cc(connCtx, rw)
if connCtx == nil {
panic("ConnContext returned nil")
}
}
tempDelay = 0
c := srv.newConn(rw)
c.setState(c.rwc, StateNew, runHooks) // before Serve can return
go c.serve(connCtx)
}
}
关键代码
c := srv.newConn(rw)
c.setState(c.rwc, StateNew) // before Serve can return
go c.serve()
newConn
// Create new connection from rwc.
func (srv *Server) newConn(rwc net.Conn) *conn {
c := &conn{
server: srv,
rwc: rwc,
}
if debugServerConnections {
c.rwc = newLoggingConn("server", c.rwc)
}
return c
}
如何分配handler
conn先解析request:c.readRequest(),获取相应的handler:handler:=c.server.Handler,即ListenAndServe的第二个参数,因为值为nil,所以默认handler=DefaultServeMux。该变量是一个路由器,用来匹配url跳转到其相应的handle函数。其中http.HandleFunc(“/“,sayhelloName)即注册了请求“/”的路由规则,当uri为“/”时,路由跳转到函数sayhelloName。DefaultServeMux会调用ServeHTTP方法,这个方法内部调用sayhelloName本身,最后写入response的信息反馈给客户端。
c.serve()
func (c *conn) serve() {
...
for {
w, err := c.readRequest()
...
serverHandler{c.server}.ServeHTTP(w, w.req)
..
}
}
2.5.2. c.readRequest()
// Serve a new connection.
func (c *conn) serve() {
...
for {
w, err := c.readRequest()
...
serverHandler{c.server}.ServeHTTP(w, w.req)
..
}
}
2.5.2. c.readRequest()
// Read next request from connection.
func (c *conn) readRequest() (w *response, err error) {
if c.hijacked() {
return nil, ErrHijacked
}
if d := c.server.ReadTimeout; d != 0 {
c.rwc.SetReadDeadline(time.Now().Add(d))
}
if d := c.server.WriteTimeout; d != 0 {
defer func() {
c.rwc.SetWriteDeadline(time.Now().Add(d))
}()
}
c.r.setReadLimit(c.server.initialReadLimitSize())
c.mu.Lock() // while using bufr
if c.lastMethod == "POST" {
// RFC 2616 section 4.1 tolerance for old buggy clients.
peek, _ := c.bufr.Peek(4) // ReadRequest will get err below
c.bufr.Discard(numLeadingCRorLF(peek))
}
req, err := readRequest(c.bufr, keepHostHeader)
c.mu.Unlock()
if err != nil {
if c.r.hitReadLimit() {
return nil, errTooLarge
}
return nil, err
}
c.lastMethod = req.Method
c.r.setInfiniteReadLimit()
hosts, haveHost := req.Header["Host"]
if req.ProtoAtLeast(1, 1) && (!haveHost || len(hosts) == 0) {
return nil, badRequestError("missing required Host header")
}
if len(hosts) > 1 {
return nil, badRequestError("too many Host headers")
}
if len(hosts) == 1 && !validHostHeader(hosts[0]) {
return nil, badRequestError("malformed Host header")
}
for k, vv := range req.Header {
if !validHeaderName(k) {
return nil, badRequestError("invalid header name")
}
for _, v := range vv {
if !validHeaderValue(v) {
return nil, badRequestError("invalid header value")
}
}
}
delete(req.Header, "Host")
req.RemoteAddr = c.remoteAddr
req.TLS = c.tlsState
if body, ok := req.Body.(*body); ok {
body.doEarlyClose = true
}
w = &response{
conn: c,
req: req,
reqBody: req.Body,
handlerHeader: make(Header),
contentLength: -1,
}
w.cw.res = w
w.w = newBufioWriterSize(&w.cw, bufferBeforeChunkingSize)
return w, nil
}
ServeHTTP(w, w.req)
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)
}
DefaultServeMux
type ServeMux struct {
mu sync.RWMutex
m map[string]muxEntry
hosts bool // whether any patterns contain hostnames
}
type muxEntry struct {
explicit bool
h Handler
pattern string
}
// NewServeMux allocates and returns a new ServeMux.
func NewServeMux() *ServeMux { return &ServeMux{m: make(map[string]muxEntry)} }
// DefaultServeMux is the default ServeMux used by Serve.
var DefaultServeMux = NewServeMux()
handler接口的定义
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
ServeMux.ServeHTTP
// ServeHTTP dispatches the request to the handler whose
// pattern most closely matches the request URL.
func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) {
if r.RequestURI == "*" {
if r.ProtoAtLeast(1, 1) {
w.Header().Set("Connection", "close")
}
w.WriteHeader(StatusBadRequest)
return
}
h, _ := mux.Handler(r)
h.ServeHTTP(w, r)
}
mux.Handler(r)
// Handler returns the handler to use for the given request,
// consulting r.Method, r.Host, and r.URL.Path. It always returns
// a non-nil handler. If the path is not in its canonical form, the
// handler will be an internally-generated handler that redirects
// to the canonical path.
//
// Handler also returns the registered pattern that matches the
// request or, in the case of internally-generated redirects,
// the pattern that will match after following the redirect.
//
// If there is no registered handler that applies to the request,
// Handler returns a ``page not found'' handler and an empty pattern.
func (mux *ServeMux) Handler(r *Request) (h Handler, pattern string) {
if r.Method != "CONNECT" {
if p := cleanPath(r.URL.Path); p != r.URL.Path {
_, pattern = mux.handler(r.Host, p)
url := *r.URL
url.Path = p
return RedirectHandler(url.String(), StatusMovedPermanently), pattern
}
}
return mux.handler(r.Host, r.URL.Path)
}
// handler is the main implementation of Handler.
// The path is known to be in canonical form, except for CONNECT methods.
func (mux *ServeMux) handler(host, path string) (h Handler, pattern string) {
mux.mu.RLock()
defer mux.mu.RUnlock()
// Host-specific pattern takes precedence over generic ones
if mux.hosts {
h, pattern = mux.match(host + path)
}
if h == nil {
h, pattern = mux.match(path)
}
if h == nil {
h, pattern = NotFoundHandler(), ""
}
return
}
3. http的执行流程总结
- 首先调用Http.HandleFunc,按如下顺序执行:
- 调用了DefaultServerMux的HandleFunc。
- 调用了DefaultServerMux的Handle。
- 往DefaultServerMux的map[string] muxEntry中增加对应的handler和路由规则。
- 调用http.ListenAndServe(“:9090”,nil),按如下顺序执行:
- 实例化Server。
- 调用Server的ListenAndServe()。
- 调用net.Listen(“tcp”,addr)监听端口。
- 启动一个for循环,在循环体中Accept请求。
- 对每个请求实例化一个Conn,并且开启一个goroutine为这个请求进行服务go c.serve()。
- 读取每个请求的内容w,err:=c.readRequest()。
- 判断handler是否为空,如果没有设置handler,handler默认设置为DefaultServeMux。
- 调用handler的ServeHttp。
- 根据request选择handler,并且进入到这个handler的ServeHTTP, mux.handler(r).ServeHTTP(w,r)
- 选择handler
- 判断是否有路由能满足这个request(循环遍历ServeMux的muxEntry)。
- 如果有路由满足,调用这个路由handler的ServeHttp。
- 如果没有路由满足,调用NotFoundHandler的ServeHttp。