【go语言 socket编程系列】一个简单的HTTP服务器及http.ListenAndServe函数

【简单的HTTP服务器】

源文件server.go中 ListenAndServe()函数的注释中有个简单的HTTP服务实现代码,如下

package main

import (
	"io"
	"log"
	"net/http"
)

func HelloServer(w http.ResponseWriter, r *http.Request) {
	io.WriteString(w, "hello ,this is from HelloServer func ")
}

func main() {
	http.HandleFunc("/hello", HelloServer)
	log.Fatal(http.ListenAndServe(":12345", nil))
}

通过浏览器 或者命令行工具可以访问

lynx  localhost:12345/hello

【http.ListenAndServe】

http.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.
// 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类型的数据,通过addr  和handler 来初始化。然后调用Server类型的成员函数 ListenAndServe()。

Server类型的定义如下,主要定义了http的一些参数,默认可为0.如上图,只初始化了 Addr 和Handler成员。

type Server struct {
	Addr      string      // TCP address to listen on, ":http" if empty
	Handler   Handler     // handler to invoke, http.DefaultServeMux if nil
	TLSConfig *tls.Config // optional TLS config, used by ServeTLS and ListenAndServeTLS

	// ReadTimeout is the maximum duration for reading the entire
	// request, including the body.
	//
	// Because ReadTimeout does not let Handlers make per-request
	// decisions on each request body's acceptable deadline or
	// upload rate, most users will prefer to use
	// ReadHeaderTimeout. It is valid to use them both.
	ReadTimeout time.Duration

	// ReadHeaderTimeout is the amount of time allowed to read
	// request headers. The connection's read deadline is reset
	// after reading the headers and the Handler can decide what
	// is considered too slow for the body.
	ReadHeaderTimeout time.Duration

	// WriteTimeout is the maximum duration before timing out
	// writes of the response. It is reset whenever a new
	// request's header is read. Like ReadTimeout, it does not
	// let Handlers make decisions on a per-request basis.
	WriteTimeout time.Duration

	// IdleTimeout is the maximum amount of time to wait for the
	// next request when keep-alives are enabled. If IdleTimeout
	// is zero, the value of ReadTimeout is used. If both are
	// zero, ReadHeaderTimeout is used.
	IdleTimeout time.Duration

	// MaxHeaderBytes controls the maximum number of bytes the
	// server will read parsing the request header's keys and
	// values, including the request line. It does not limit the
	// size of the request body.
	// If zero, DefaultMaxHeaderBytes is used.
	MaxHeaderBytes int

	// TLSNextProto optionally specifies a function to take over
	// ownership of the provided TLS connection when an NPN/ALPN
	// protocol upgrade has occurred. The map key is the protocol
	// name negotiated. The Handler argument should be used to
	// handle HTTP requests and will initialize the Request's TLS
	// and RemoteAddr if not already set. The connection is
	// automatically closed when the function returns.
	// If TLSNextProto is not nil, HTTP/2 support is not enabled
	// automatically.
	TLSNextProto map[string]func(*Server, *tls.Conn, Handler)

	// ConnState specifies an optional callback function that is
	// called when a client connection changes state. See the
	// ConnState type and associated constants for details.
	ConnState func(net.Conn, ConnState)

	// ErrorLog specifies an optional logger for errors accepting
	// connections and unexpected behavior from handlers.
	// If nil, logging goes to os.Stderr via the log package's
	// standard logger.
	ErrorLog *log.Logger

	// Has unexported fields.
}

通过 go doc Server 命令 还可以快速看到Server类型的成员函数

func (srv *Server) Close() error
func (srv *Server) ListenAndServe() error
func (srv *Server) ListenAndServeTLS(certFile, keyFile string) error
func (srv *Server) RegisterOnShutdown(f func())
func (srv *Server) Serve(l net.Listener) error
func (srv *Server) ServeTLS(l net.Listener, certFile, keyFile string) error
func (srv *Server) SetKeepAlivesEnabled(v bool)
func (srv *Server) Shutdown(ctx context.Context) error
 

Server类型的ListenAndServe()源码如下

2627 func (srv *Server) ListenAndServe() error {
2628         addr := srv.Addr
2629         if addr == "" {
2630                 addr = ":http"
2631         }
2632         ln, err := net.Listen("tcp", addr)
2633         if err != nil {
2634                 return err
2635         }
2636         return srv.Serve(tcpKeepAliveListener{ln.(*net.TCPListener)})
2637 }

首先获取其成语的 Addr,即ip port, 然后调用net.Listen() 函数,实现端口监听。

在返回 Server类型的Serve成员方法时,有个 tcpKeepAliveListener{ln.(*net.TCPListener)} 操作。其中tcpKeepAliveListener 类型的源码如下,只有一个 Accept()成员方法。通过TCPListener 类型的AcceptTCP()成员方法返回  *TCPConn类型数据,然后调用*TCPConn的成员方法SetKeepAlive() 来开启超时时间的设置。

3115 type tcpKeepAliveListener struct {
3116         *net.TCPListener
3117 }
3118 
3119 func (ln tcpKeepAliveListener) Accept() (c net.Conn, err error) {
3120         tc, err := ln.AcceptTCP()
3121         if err != nil {
3122                 return
3123         }
3124         tc.SetKeepAlive(true)
3125         tc.SetKeepAlivePeriod(3 * time.Minute)
3126         return tc, nil
3127 }

回到 Server 类型的ListenAndServe()方法的源码 return srv.Serve(tcpKeepAliveListener{ln.(*net.TCPListener)})。(ln.(*net.TCPListener)为类型断言语句)。Server类型的Serve方法,源码如下。

2678 func (srv *Server) Serve(l net.Listener) error {
2679         defer l.Close()
2680         if fn := testHookServerServe; fn != nil {
2681                 fn(srv, l)
2682         }
2683         var tempDelay time.Duration // how long to sleep on accept failure
2684 
2685         if err := srv.setupHTTP2_Serve(); err != nil {
2686                 return err
2687         }
2688 
2689         srv.trackListener(l, true)
2690         defer srv.trackListener(l, false)
2691 
2692         baseCtx := context.Background() // base is always background, per Issue 16220
2693         ctx := context.WithValue(baseCtx, ServerContextKey, srv)
2694         for {
2695                 rw, e := l.Accept()
2696                 if e != nil {
2697                         select {
2698                         case <-srv.getDoneChan():
2699                                 return ErrServerClosed
2700                         default:
2701                         }
2702                         if ne, ok := e.(net.Error); ok && ne.Temporary() {
2703                                 if tempDelay == 0 {
2704                                         tempDelay = 5 * time.Millisecond
2705                                 } else {
2706                                         tempDelay *= 2
2707                                 }
2708                                 if max := 1 * time.Second; tempDelay > max {
2709                                         tempDelay = max
2710                                 }
2711                                 srv.logf("http: Accept error: %v; retrying in %v", e, tempDelay)
2712                                 time.Sleep(tempDelay)
2713                                 continue
2714                         }
2715                         return e
2716                 }
2717                 tempDelay = 0
2718                 c := srv.newConn(rw)
2719                 c.setState(c.rwc, StateNew) // before Serve can return
2720                 go c.serve(ctx)
2721         }
2722 }

代码很长且逻辑较多,我们暂且简化下,先梳理大体的逻辑,后续再展开研究。大量精简后的代码如下

2678 func (srv *Server) Serve(l net.Listener) error {
2679         defer l.Close()
2694         for {
2695                 rw, e := l.Accept()              
2716                 }
2718                 c := srv.newConn(rw)
2720                 go c.serve(ctx)
2721         }
2722 }

即 主体通过一个for循环,通过Accept方法监听请求,收到请求后创建一个新的conn类型数据 ,然后通过go cserver() 实现并发处理。处理完请求后 通过defer l.close()  回收资源。

到此大致梳理完了 http.ListenAndServe()的基本逻辑。回到文字开头的代码 http.ListenAndServe(":12345", nil)

1、执行ListenAndServe(":12345",nil)后,会创建一个Server类型数据。

2、通过“:12345” 来初始化 Server的 Addr成员。Handler成员为nil

3、调用Server类型的成员函数ListenAndServe()。并通过未导出的tcpKeepAliveListener 类型做了接口转换。

      tcpKeepAliveListener类型即*net.TCPListener,用于超时时间的设定

4、调用Server类型的Serve方法,实现接口的监听 及并发处理请求。

即httpListenAndServe()函数 封装了 底层TCP通信的实现逻辑。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值