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

时间:2025-03-26 14:40:21

【简单的HTTP服务器】

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

package main

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

func HelloServer(w , r *) {
	(w, "hello ,this is from HelloServer func ")
}

func main() {
	("/hello", HelloServer)
	((":12345", nil))
}

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

lynx  localhost:12345/hello

【】

()源码如下

// 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类型的数据,通过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,  if nil
	TLSConfig * // 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 

	// 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 

	// 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 

	// 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 

	// 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, *, 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(, ConnState)

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

	// 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 ) error
func (srv *Server) ServeTLS(l , certFile, keyFile string) error
func (srv *Server) SetKeepAlivesEnabled(v bool)
func (srv *Server) Shutdown(ctx ) error
 

Server类型的ListenAndServe()源码如下

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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