在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
func (srv *Server) Serve(l net.Listener) error {defer l.Close()
var tempDelay time.Duration // how long to sleep on accept failure
for {
rw, e := l.Accept()
if e != nil {
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
}
log.Printf("http: Accept error: %v; retrying in %v", e, tempDelay)
time.Sleep(tempDelay)
continue
}
return e
}
tempDelay = 0
if srv.ReadTimeout != 0 {
rw.SetReadDeadline(time.Now().Add(srv.ReadTimeout))
}
if srv.WriteTimeout != 0 {
rw.SetWriteDeadline(time.Now().Add(srv.WriteTimeout))
}
c, err := srv.newConn(rw)
if err != nil {
continue
}
go c.serve()
}
panic("not reached")
}
监控之后如何接收客户端的请求呢?上面代码执行监控端口之后,调用了srv.Serve(net.Listener)函数,这个函数就是处理接收客户端的请求信息。这个函数里面起了一个 for{},首先通过 Listener 接收请求,其次创建一个 Conn,最后单独开了一个goroutine,把这个请求的数据当做参数扔给这个 conn 去服务:go c.serve()。这个就是高并发体现了,用户的每次请求都是在一个新的 goroutine 去服务,相互不影响。那么如何具体分配到相应的函数来处理请求呢?
conn 首先会解析 request:c.readRequest(),然后获取相应的 handler:handler := c.server.Handler,也就是我们刚才在调用函数ListenAndServe 时候的第二个参数,我们前面例子传递的是 nil,也就是为空,那么默认获取 handler = DefaultServeMux,那么这个变量用来做什么的呢?对,这个变量就是一个路由器,它用来匹配 url 跳转到其相应的 handle 函数,那么这个我们有设置过吗?有,我们调用的代码里面第一句不是调用了 http.HandleFunc("/", sayhelloName)嘛。
这个作用就是注册了请求/的路由规则,当请求 uri 为"/",路由就会转到函数 sayhelloName,DefaultServeMux会调用 ServeHTTP 方法,这个方法内部其实就是调用 sayhelloName 本身,最后通过写入response 的信息反馈到客户端。
Go 的 http 有两个核心功能:Conn、ServeMux
type Handler interface {
ServeHTTP(ResponseWriter, *Request) // 路由实现器
}
Handler 是一个接口,但是前一小节中的 sayhelloName 函数并没有实现 ServeHTTP 这个接口,为什么能添加呢?原来在 http 包里面还定义了一个类型 HandlerFunc,我们定义的函 数 sayhelloName 就是这个 HandlerFunc 调用之后的结果,这个类型默认就实现了ServeHTTP 这个接口,即我们调用了 HandlerFunc(f),强制类型转换 f 成为 HandlerFunc 类型,这样 f 就拥有了 ServHTTP 方法。
type HandlerFunc func(ResponseWriter, *Request)
// ServeHTTP calls f(w, r)
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
f(w, r)
}
按顺序做了几件事:
1 调用了 DefaultServerMux 的 HandleFunc
2 调用了 DefaultServerMux 的 Handle3 往 DefaultServeMux 的 map[string]muxEntry 中增加对应的 handler 和路由规则
• 其次调用 http.ListenAndServe(":9090", nil)
按顺序做了几件事情:
1 实例化 Server
2 调用 Server 的 ListenAndServe()
3 调用 net.Listen("tcp", addr)监听端口
4 启动一个 for 循环,在循环体中 Accept 请求
5 对每个请求实例化一个 Conn,并且开启一个 goroutine 为这个请求进行服务 go c.serve()
6 读取每个请求的内容 w, err := c.readRequest()
7 判断 handler 是否为空,如果没有设置 handler(这个例子就没有设置
handler),handler 就设置为 DefaultServeMux
8 调用 handler 的 ServeHttp
9 在这个例子中,下面就进入到 DefaultServerMux.ServeHttp
10 根据 request 选择 handler,并且进入到这个 handler 的 ServeHTTP
mux.handler(r).ServeHTTP(w, r)
11 选择 handler:
A 判断是否有路由能满足这个 request(循环遍历 ServerMux 的 muxEntry)
B 如果有路由满足,调用这个路由 handler 的 ServeHttp
C 如果没有路由满足,调用 NotFoundHandler 的 ServeHttp
|
请发表评论