net/http源码分析
一、构建一个简单的web服务器
如何用go实现一个最简单的http server呢?
package main
import (
"fmt"
"net/http"
)
func hello(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "Hello World.")
}
func main() {
http.HandleFunc("/", hello)
http.ListenAndServe(":3000", nil)
}
这里的服务器只提供了根目录的路由功能。而HandleFunc与ListenAndServer作为http包最基础的函数是如何实现的呢?当然要看源码才能分析其中的奥秘。
二、http流程分析
http采用的client-server架构。client首先发送request到服务端,然后server接受request,根据路由处理并返回相应的response。最后client收到response以后会把相应的页面通过浏览器渲染出来。而这里我们主要对server端进行分析,那么server实现的功能是1.不断监听接收端口2.通过多路分解器处理request返回response也就对应了上述的两个函数。
三、http.HandleFunc
func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
DefaultServeMux.HandleFunc(pattern, handler)
}
源码如上,它会调用DefaultServeMux的功能HandleFunc。而handler的定义是func(ResponseWriter, *Request)的。
接受request中最重要的就是用多路分解器(Multiplexer)实现路由功能了。Go有自己内置的mutilplexer -DefautServeMux
,它是ServeMux结构的一个实例,并实现了Handler接口
ServeMux会使用handler并调用其ServeHTTP方法处理请求并返回响应。
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
而 ServeHTTP 函数内部则会调用我们自定义的处理函数对客户端的请求信息进行处理。
四、http.ListenAndServe
func ListenAndServe(addr string, handler Handler) error {
server := &Server{Addr: addr, Handler: handler}
return server.ListenAndServe()
}
ListenAndServe源码如上,http.ListenAndServe 是先利用端口号和处理函数初始化一个 Server 结构实例,然后通过调用这个实例的 ListenAndServe() 来实现监听功能的。
server结构体如下:
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
}
其中存储了服务器处理请求常见的字段。其中Handler字段也保留Handler接口。如果Server接口没有提供Handler结构对象,那么会使用DefautServeMux做multiplexer。
而Server的ListenAndServe功能如下。首先先用TCP搭建一个服务,然后监听设置的端口。
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)})
}