Go 语言实现的 Web 服务工作方式与其他形式下的 Web 工作方式并没有什么不同,具体流程如下:
—— http包执行流程
Request:来自用户的请求信息,包括 post、get、Cookie、url 等。
Response:服务器返回给客户端的信息。
Connect:用户的每次的请求连接
Handler:处理请求和生成返回信息的处理逻辑
根据上图,Go 语言中的 http 包具体做了这么三个操作:
- 创建 Listen Socket,监听指定端口,等待客户端请求。
- Listen Socket 接受客户端请求,得到 Client Socket,接下来通过 Client Socket与客户端通信
- 处理客户端请求。首先从 Client Socket 获取 HTTP 请求数据,然后交给相应的 handler 处理请求,handler 处理完毕后再通过 Client Socket 返回给客户端。
接着我们从代码的角度来看一下这三个操作是如何实现的:
一,监听端口
在 Go 语言中只需要通过调用 ListenAndServe 方法即可设置监听端口:
func main() { ???http.HandleFunc("/", sayhelloName) ??????//设置访问的路由 ???????err := http.ListenAndServe(":9090", nil) //设置监听的端口 ???if err != nil { ???????log.Fatal("ListenAndServe: ", err) ???}}
我们接着看一下 ListenAndServe 方法的具体实现,看一下它是如何实现监听端口的:
// ListenAndServe listens on the TCP network address addr and then calls// Serve with handler to handle requests on incoming connections.// Accepted connections are configured to enable TCP keep-alives.//// The handler is typically nil, in which case the DefaultServeMux is used.//// ListenAndServe always returns a non-nil error.func ListenAndServe(addr string, handler Handler) error { ???server := &Server{Addr: addr, Handler: handler} ???return server.ListenAndServe()}
通过查看该方法的源码,可以发现该方法初始化了一个 server 对象,并调用了该 server 对象的 ListenAndServe() 方法:
// ListenAndServe listens on the TCP network address srv.Addr and then// calls Serve to handle requests on incoming connections.// Accepted connections are configured to enable TCP keep-alives.//// If srv.Addr is blank, ":http" is used.//// ListenAndServe always returns a non-nil error. After Shutdown or Close,// the returned error is ErrServerClosed.func (srv *Server) ListenAndServe() error { ???if srv.shuttingDown() { ???????return ErrServerClosed ???} ???addr := srv.Addr ???if addr == "" { ???????addr = ":http" ???} ???ln, err := net.Listen("tcp", addr) //底层使用tcp协议搭建了一个服务,然后监听所设置的端口 ???if err != nil { ???????return err ???} ???return srv.Serve(tcpKeepAliveListener{ln.(*net.TCPListener)})}
在这个方法中调用了 net.Listen("tcp", addr) 来监听端口
二,接收客户端请求
在完成了对端口的监听之后,再通过调用 srv.Serve(net.Listener) 方法来处理接收客户端的请求消息。
// Serve accepts incoming connections on the Listener l, creating a// new service goroutine for each. The service goroutines read requests and// then call srv.Handler to reply to them.//// HTTP/2 support is only enabled if the Listener returns *tls.Conn// connections and they were configured with "h2" in the TLS// Config.NextProtos.//// Serve always returns a non-nil error and closes l.// After Shutdown or Close, the returned error is ErrServerClosed.func (srv *Server) Serve(l net.Listener) error { ???... ???for { ???????rw, e := l.Accept() //在循环体中阻塞等待请求 ???????if e != nil { ???????????select { ???????????case <-srv.getDoneChan(): ???????????????return ErrServerClosed ???????????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 ???????} ???????... ???????c := srv.newConn(rw) ???????c.setState(c.rwc, StateNew) // before Serve can return ???????go c.serve(ctx) ???}}
在这个方法中,启动了一个 for 循环使 Listener 不断地接收来自客户端的请求,并且对每一个请求都实例化一个 Conn,并开启一个 goroutine 来为这个请求进行服务 go c.serve()。用户的每一次请求都是在一个新的 goroutine中服务,互相不影响。
三,为不同的请求分配处理逻辑
对于来自客户端的不同请求,服务器端需要根据情况来分配相对应的函数进行处理。
在之前的 main
方法中,我们调用了 http.ListenAndServe(":9090", nil)
来监听端口,而第二个参数传入的是 nil,那么这个参数是干嘛用的呢?
func ListenAndServe(addr string, handler Handler) error { ???server := &Server{Addr: addr, Handler: handler} ???return server.ListenAndServe()}type Server struct { ???Addr ???string ?????// 监听的地址和端口 默认为":http" ???Handler Handler ????// 路由管理,如果为nil,则默认为http.DefaultServeMux ???ReadTimeout time.Duration //读的最大超时时间 ???WriteTimeout time.Duration //写的最大超时时间 ???MaxHeaderBytes int ????????//请求头的最大长度 ???TLSConfig *tls.Config ?????// 配置TLS ???...}
从源码中的注释可以看出,当初始化 Server 时,如果不指定 Handler,则默认获取 Handler = http.DefaultServeMux。这个 Handler 就是一个路由器,它用来匹配 url 跳转到其相应的 handle 函数。
// DefaultServeMux is the default ServeMux used by Serve.var DefaultServeMux = &defaultServeMuxvar defaultServeMux ServeMux
详细流程如下:
—— http处理连接流程
Go http包执行流程
原文地址:https://www.cnblogs.com/liyutian/p/10144584.html