One day Learning _go language http Server (source code Analysis)

Source: Internet
Author: User
This is a creation in Article, where the information may have evolved or changed.

HTTP Server in the Go language:

HTTP server, as its name implies, is a server that supports HTTP protocols, and HTTP is a simple request-response protocol that typically runs on top of TCP. The client sends the request to the server for a corresponding response.


HTTP

HTTP Service Simple Implementation

package mainimport (    "fmt"    "net/http")//③处理请求,返回结果func Hello(w http.ResponseWriter, r *http.Request) {    fmt.Fprintln(w, "hello world")}func main() {    //①路由注册    http.HandleFunc("/", Hello)     //②服务监听    http.ListenAndServe(":8080", nil)}


You think it's over, and it's just the beginning.

SOURCE Analysis

① Routing Registration
The Handlefunc method in HTTP, which is used primarily to register routes

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

What is Defaultservemux?
Defaultservemux is an example of Servemux.
What is Servemux again?

// DefaultServeMux is the default ServeMux used by Serve.var DefaultServeMux = &defaultServeMuxvar defaultServeMux ServeMuxtype ServeMux struct {    mu    sync.RWMutex    m     map[string]muxEntry    hosts bool }type muxEntry struct {    explicit bool    h        Handler    pattern  string}

Servemux mainly through the map[string]muxentry, to store the specific URL pattern and handler (this handler is to implement the type of handler interface). Match the route by implementing the handler Servehttp method (this is the source below)
Many places involve handler, so what is handler?

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

This interface can be considered a hub for HTTP server

func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {    mux.Handle(pattern, HandlerFunc(handler))}type HandlerFunc func(ResponseWriter, *Request)func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {    f(w, r)}

As you can see from the code, Handlerfunc is a function type and implements the handler interface. When the Hello is converted to the Handlerfunc type by calling Handlefunc (), it means that the Hello function also implements the Servehttp method.
Servemux method of handle:

Func (Mux *servemux) Handle (pattern string, handler handler) {Mux.mu.Lock () defer mux.mu.Unlock () if pattern = =    "{Panic (" http:invalid pattern "+ pattern)} if handler = = nil {Panic (" Http:nil handler ")}        If mux.m[pattern].explicit {panic ("Http:multiple registrations for" + pattern)} If mux.m = nil { MUX.M = Make (Map[string]muxentry)}//Bind handler and pattern patterns to//map[string]muxentry's map mux.m[pattern] = Muxe Ntry{explicit:true, H:handler, Pattern:pattern} if pattern[0]! = '/' {mux.hosts = true}//This is a binding static directory and does not make    For this film focus. N: = Len (pattern) if n > 0 && pattern[n-1] = = '/' &&!mux.m[pattern[0:n-1]].explicit {path: = Pattern if pattern[0]! = '/' {path = pattern[strings. Index (Pattern, "/"):]} URL: = &url. Url{path:path} mux.m[pattern[0:n-1]] = Muxentry{h:redirecthandler (URL. String (), statusmovedpermanently), Pattern:pattern}    }} 

The process above completes the routing registration.
② Service Monitoring

type Server struct {    Addr         string            Handler      Handler           ReadTimeout  time.Duration     WriteTimeout time.Duration     TLSConfig    *tls.Config       MaxHeaderBytes int    TLSNextProto map[string]func(*Server, *tls.Conn, Handler)    ConnState func(net.Conn, ConnState)    ErrorLog *log.Logger    disableKeepAlives int32        nextProtoOnce     sync.Once     nextProtoErr      error     }func ListenAndServe(addr string, handler Handler) error {    server := &Server{Addr: addr, Handler: handler}    return server.ListenAndServe()}//初始化监听地址Addr,同时调用Listen方法设置监听。//最后将监听的TCP对象传入Serve方法:func (srv *Server) ListenAndServe() error {        addr := srv.Addr        if addr == "" {            addr = ":http"        }        ln, err := net.Listen("tcp", addr)        if err != nil {            return err        }        return srv.Serve(tcpKeepAliveListener{ln.(*net.TCPListener)})    }

Serve (L net. Listener) for each request to open the Goroutine design, to ensure the high concurrency of Go.

Func (SRV *server) Serve (l net. Listener) Error {defer l.close () if fn: = Testhookserverserve; fn! = nil {fn (SRV, L)} var Tempdelay Time. Duration//How long-to-sleep on accept failure If err: = Srv.setuphttp2_serve (); Err! = Nil {return err} srv.tracklistener (L, True) defer Srv.tracklistener (L, false) Basectx: = Conte Xt. Background ()//base is always Background, per Issue 16220 CTX: = context. Withvalue (Basectx, Servercontextkey, srv) CTX = context. Withvalue (CTX, Localaddrcontextkey, L.ADDR ())//Turn on loop for monitoring for {///through the Accept method of listener to obtain the connection data rw, e: = L . Accept () if E! = Nil {Select {case <-srv.getdonechan (): Return ERRSERVERC losed default:} 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} srv.logf ("Http:accept error:%v; Retrying in%v ", E, Tempdelay) time. Sleep (Tempdelay) Continue} return e} tempdelay = 0//Through the obtained connection data , create Newconn Connection object c: = Srv.newconn (rw) c.setstate (C.RWC, statenew)//Before Serve can return//open Start Goroutine send connection request go C.serve (CTX)}}

Serve () is the core and reads the corresponding connection data for allocation

Func (c *conn) serve (CTX context. Context) {c.remoteaddr = C.rwc.remoteaddr ().            String ()//connection close related processing defer func () {if err: = Recover (); Err! = Nil && Err! = Erraborthandler { Const SIZE = << BUF: = Make ([]byte, size) buf = Buf[:runtime. Stack (BUF, false)] C.SERVER.LOGF ("Http:panic serving%v:%v\n%s", c.remoteaddr, Err, BUF)} if! C.hijacked () {c.close () c.setstate (C.RWC, Stateclosed)}} () ... ctx, Cancelctx: = Context. Withcancel (CTX) C.cancelctx = Cancelctx defer cancelctx () C.R = &connreader{conn:c} C.BUFR = Newbufioread ER (C.R) C.BUFW = Newbufiowritersize (Checkconnerrorwriter{c}, 4<<10) for {//Read client's request W, err: = C . Readrequest (CTX) if c.r.remain! = C.server.initialreadlimitsize () {//If we read any bytes off the WIR            E, we ' re active.     C.setstate (C.RWC, Stateactive)}           ....//handling the status of the network data//Expect Continue support req: = W.req if Req.ex. Pectscontinue () {if Req. Protoatleast (1, 1) && req. ContentLength! = 0 {//Wrap the Body reader with one, replies on the connection req. Body = &expectcontinuereader{readcloser:req. Body, Resp:w}}} else if req.        Header.get ("Expect")! = "" {w.sendexpectationfailed () return} c.curreq.store (W) If Requestbodyremains (req. Body) {registeronhiteof (req). Body, W.conn.r.startbackgroundread)} else {if w.conn.bufr.buffered () > 0 {w.conn.r. Closenotifyfrompipelinedrequest ()} w.conn.r.startbackgroundread ()}//Call Serverhandler {C.server}. Servehttp (W, w.req)//Method processing request Serverhandler{c.server}. Servehttp (W, W.req) w.cancelctx () if c.hijacked () {REturn} w.finishrequest () if!w.shouldreuseconnection () {if W.requestbodylimithit | | w.cl Osedrequestbodyearly () {c.closewriteandwait ()} return} c.setstate (c.        RWC, Stateidle) C.curreq.store ((*response) (nil)) if!w.conn.server.dokeepalives () {return If d: = C.server.idletimeout (); D! = 0 {c.rwc.setreaddeadline (time. Now (). ADD (d)) If _, Err: = C.bufr.peek (4); Err! = nil {return}} c.rwc.setreaddeadline (time. time{})}}

③ processing requests, returning results
The Serverhandler primarily initializes the routing multiplexer. If the server object does not specify handler, the default Defaultservemux is used as the routing multiplexer. and calls the Servehttp method that initializes the handler.

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

Here is the specific code for the previously mentioned matching route

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}//Match registered to the handler function on the route h , _: = Mux. Handler (R)//Call the Servehttp method of the Handler function//That is, the Hello function, and then write the data to HTTP.    The Responsewriter//object is returned to the client.        H.servehttp (W, R)}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)}func (Mux *servemux) handler (host, path string) (H handler, pattern string) {Mux.mu.RLock () defer MUX.MU.RUNL Ock ()//Host-specific pattern takes precedence over generic ones if mux.hosts {//such as 127.0.0.1/hello h, pattern = mux.match (host + Path)} if H = = Nil {//as/hello h, pattern = Mux.match (PATH)} if H = = Nil {h, pattern = Notfoundhandler (), ""} return}func (Mux *servemux) match (Path String) (H Handler, pattern string) {var n = 0 for k, V: = Range mux.m {if!pathmatch (k, path) {continue}//Find out registration by Iteration M        The Patten mode of the route//handler function that matches the actual URL and returns. if H = = Nil | | Len (k) > N {n = len (k) h = v.h pattern = v.pattern}} return}func Pathm Atch (pattern, path string) bool {if len (pattern) = = 0 {//should not happen return false} N: = L En (pattern)//If the registration mode returns true as the request URI, False if pattern[n-1]! = '/' {return pattern = = Path}// Static file match return len (path) >= n && path[0:n] = = Pattern}

Writing data to clients

//主要代码,通过层层封装才走到这一步func (w checkConnErrorWriter) Write(p []byte) (n int, err error) {    n, err = w.c.rwc.Write(p)    if err != nil && w.c.werr == nil {        w.c.werr = err        w.c.cancelCtx()    }    return}

Serverhandler{c.server}. Servehttp (W, W.req) when the request is finished, the relevant logic for the connection break begins.


Summarize
The go language manages routing through a SERVEMUX-implemented routing multiplexer. A handler interface is provided with a Servehttp method that implements the handler interface function that can handle the actual request and return response.
The connection bridge between the Servemux and handler functions is the handler interface. Servemux's Servehttp method implements a function that looks for the handler of the registered route and calls the Servehttp method of the handler.
So, handler interface is an important hub.

Simply comb the entire request response process, such as


HTTP Server flowchart
Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.