Golang:net初窥

Golang中的net包

func main() {  
    http.HandleFunc("/", sayHello)  
    err := http.ListenAndServe("localhost:8080", http.DefaultServeMux)  
    if err != nil {  
       log.Fatal("ListenAndServer: ", err)  
    } 
} 

其中http.HandleFunc("/", sayHello)实现如下

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

其中DefaultServeMux.HandleFunc(pattern, handler)实现如下

func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
    //TODO
    mux.Handle(pattern, HandlerFunc(handler))
}

这里HandlerFunc签名和ServerHTTP一样,因此可以认为,HandlerFunc已经实现了Handler接口,因此可以作为mux.Handle()的第二个参数。本来HandleFunc()中的传入参数handler也可以作为其第二参数,但mux.Handle()它有希望接收的是Handler类型的(存疑?),因此进行类型转换。

补充:这里的mux.Handle()HandlerFunc()实现如下

func (mux *ServeMux) Handle(pattern string, handler Handler) {
    //TODO
}

type HandlerFunc func(ResponseWriter, *Request)

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

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

回到主线,看下mux.Handle(pattern, HandlerFunc(handler))是如何处理的:

//类型定义
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
}

//处理函数
func (mux *ServeMux) Handle(pattern string, handler Handler) {
    //加锁
    mux.mu.Lock()
    defer mux.mu.Unlock()
    //无效值处理
    if pattern == "" {
        panic("http: invalid pattern")
    }
    if handler == nil {
        panic("http: nil handler")
    }
    //取map,如果对应的pattern有value,返回ture,表示这个pattern已经有对应的处理函数了,不能再次注册绑定。
    if _, exist := mux.m[pattern]; exist {
        panic("http: multiple registrations for " + pattern)
    }
    //注册路由和处理函数
    if mux.m == nil {
        mux.m = make(map[string]muxEntry)
    }
    e := muxEntry{h: handler, pattern: pattern}
    mux.m[pattern] = e

    //如果路由最后是'/',
    if pattern[len(pattern)-1] == '/' {
        mux.es = appendSorted(mux.es, e)
    }
    //如果路由开头是'/',
    if pattern[0] != '/' {
        mux.hosts = true
    }
}

至此,路由规则和对应的处理函数就一一对应然后存放在了mux.m中。

下面就开始服务器开启监听,即http.ListenAndServe("localhost:8080", http.DefaultServeMux),没错,终于进行到了第二行。

这里的http.DefaultServeMux其实是:

var DefaultServeMux = &defaultServeMux  //实例化
var defaultServeMux ServeMux

原来它是空的ServeMux换了一个名字。

奇怪,第二个参数接收Handler,为什么传入的是ServeMux呢,原来,ServeMux实现了Handler接口。

func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) {  
    //TODO
}

回到主线,这里的http.ListenAndServe()如下:

func ListenAndServe(addr string, handler Handler) error {  
    server := &Server{Addr: addr, Handler: handler}  
    return server.ListenAndServe()  
}
...
type Server struct {
    Addr string
    Handler Handler
    ...
}
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)
}

原来是调用net中的Listen来监听addr,这里的Listen会开启一个监听socket,并返回该socket,即ln。接下来就进入到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 {
       //  Accept()阻塞,直到接收到新的客户端连接
       rw, err := l.Accept()  
       //如果出现问题
       if err != nil {  
          //服务器已关闭
          if srv.shuttingDown() {  
             return ErrServerClosed  
          }  
          //连接超时,重试
          if ne, ok := err.(net.Error); ok && ne.Temporary() {  
             //重试延时逻辑,不超过1s
             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)  
    }  
}

如果没错误,直接就Accept后,进入c := srv.newConn(rw),如下,发现只是将rw读写socket和Server组装在一起返回

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

然后开启一个goroutine执行c.serve(connCtx)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值