Go Web服务器代码流
我正在使用Go using net/HTTP包创建一个简单的web服务器。 简单的代码如下所示:Go Web服务器代码流,go,Go,我正在使用Go using net/HTTP包创建一个简单的web服务器。 简单的代码如下所示: package main import ( "fmt" "net/http" ) type hotdog int func (m hotdog) ServeHTTP(w http.ResponseWriter, r *http.Request) { fmt.Fprintln(w, "Any code you want in this func") } func main()
package main
import (
"fmt"
"net/http"
)
type hotdog int
func (m hotdog) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Any code you want in this func")
}
func main() {
var d hotdog
http.ListenAndServe(":8080", d)
}
我想知道引擎盖下发生了什么?
如果我没有错的话
ListenAndServe()接受地址和处理程序,此函数在库中运行
func ListenAndServe(addr string, handler Handler) error {
server := &Server{Addr: addr, Handler: handler}
return server.ListenAndServe()
}
在这个函数调用ListendServe之后
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)})
}
现在调用Serve函数。但是我无法理解这个参数(tcpKeepAliveListener{ln(*net.TCPListener)}
)是如何转换为
服务函数中的(l net.Listener
)
func (srv *Server) Serve(l net.Listener) error {
defer l.Close()
if fn := testHookServerServe; fn != nil {
fn(srv, l)
}
var tempDelay time.Duration // how long to sleep on accept failure
if err := srv.setupHTTP2_Serve(); err != nil {
return err
}
srv.trackListener(l, true)
defer srv.trackListener(l, false)
baseCtx := context.Background() // base is always background, per Issue 16220
ctx := context.WithValue(baseCtx, ServerContextKey, srv)
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
}
tempDelay = 0
c := srv.newConn(rw)
c.setState(c.rwc, StateNew) // before Serve can return
go c.serve(ctx)
}
}
func(srv*Server)服务(l net.Listener)错误{
延迟l.关闭()
如果fn:=testHookServerServe;fn!=nil{
fn(srv,l)
}
var tempDelay time.Duration//接受失败时的睡眠时间
如果错误:=srv.setupHTTP2_Serve();错误!=nil{
返回错误
}
srv.trackListener(l,true)
延迟srv.trackListener(l,false)
baseCtx:=context.Background()//根据16220期,base始终是Background
ctx:=上下文.WithValue(baseCtx、ServerContextKey、srv)
为了{
rw,e:=l.Accept()
如果e!=nil{
挑选{
case max{
tempDelay=max
}
logf(“http:Accept错误:%v;在%v中重试”,e,tempDelay)
时间。睡眠(临时延迟)
持续
}
返回e
}
tempDelay=0
c:=srv.newConn(rw)
c、 setState(c.rwc,StateNew)//在服务返回之前
去发球(ctx)
}
}
调用的处理程序在哪里?正如他们已经评论的那样,
net.Listener
类型是一个接口,tcpkeepalivellistener
满足该接口,因此该类型是正确的
然后,要回答有关处理程序调用位置的问题,您需要深入了解代码流:
您发布的最后一段代码中的行go c.serve(ctx)
正在调用conn.serve()
:
这是一个函数包装器,然后为之前的相应处理程序集调用ServeHTTP
:
func (sh serverHandler) ServeHTTP(rw ResponseWriter, req *Request) {
handler := sh.srv.Handler
if handler == nil {
handler = DefaultServeMux
}
if req.RequestURI == "*" && req.Method == "OPTIONS" {
handler = globalOptionsHandler{}
}
handler.ServeHTTP(rw, req)
}
tcpKeepAliveListener
是一个net.Listener
。您必须进一步遵循代码才能找到调用处理程序的位置。事实上,更具体地说,net.Listener
是一个接口,tcpKeepAliveListener
实现了该接口。您能更详细地说明这一行tcpKeepAliveListener{ln(*net.TCPListener)}tcsKeepAlive是struct类型的,所以我们在这里初始化它,但是它是如何工作的{ln(*net.TCPListener)}@kartik:你能比“它是如何工作的”更具体一点吗?由net.Listen
返回的ln
是一个*net.TCPListener
,它被断言为在tcpKeepAliveListener
@kartik中使用,也许这可以澄清一点:谢谢我了解了Handler
// serverHandler delegates to either the server's Handler or
// DefaultServeMux and also handles "OPTIONS *" requests.
type serverHandler struct {
srv *Server
}
func (sh serverHandler) ServeHTTP(rw ResponseWriter, req *Request) {
handler := sh.srv.Handler
if handler == nil {
handler = DefaultServeMux
}
if req.RequestURI == "*" && req.Method == "OPTIONS" {
handler = globalOptionsHandler{}
}
handler.ServeHTTP(rw, req)
}
func (sh serverHandler) ServeHTTP(rw ResponseWriter, req *Request) {
handler := sh.srv.Handler
if handler == nil {
handler = DefaultServeMux
}
if req.RequestURI == "*" && req.Method == "OPTIONS" {
handler = globalOptionsHandler{}
}
handler.ServeHTTP(rw, req)
}