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)