socket互動過程:
)
golang建立http伺服器的差不多兩步:
註冊路由,提供url和handle函數的對映
//範例
http.HandleFunc("/", indexHeander)
http.HandleFunc("/index", indexHandle)
範例化server,監聽埠,建立連線
log.Fatal(http.ListenAndServe(":8999", nil))
先講講用來註冊路由的HandleFunc函數.
HandleFunc函數結構簡單:使用預設的多路複用器註冊路由
可以看到,DefaultServeMux就是一個ServeMux的範例
//DefaultServeMux宣告如下
var DefaultServeMux = &defaultServeMux
var defaultServeMux ServeMux
type ServeMux struct {
mu sync.RWMutex//讀寫鎖
m map[string]muxEntry
es []muxEntry // slice of entries sorted from longest to shortest.
hosts bool // whether any patterns contain hostnames
}
...
func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
DefaultServeMux.HandleFunc(pattern, handler)
}
在此前提下,可以發現HandleFunc實際呼叫的是DefaultServeMux的Handle()函數
func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
...省略部分判斷邏輯
mux.Handle(pattern, HandlerFunc(handler))
}
ServeMux.Handle主要函數如下(省略部分異常)
(MuxEntry結構如下)
type muxEntry struct {
h Handler //處理常式
pattern string //URL
}
....
func (mux *ServeMux) Handle(pattern string, handler Handler) {
mux.mu.Lock()
defer mux.mu.Unlock()
...判斷邏輯
if mux.m == nil {
mux.m = make(map[string]muxEntry)
}
e := muxEntry{h: handler, pattern: pattern}
//使用URL進行Hash對映
mux.m[pattern] = e
if pattern[len(pattern)-1] == '/' {
//使用二分查詢將e插入到mux.es中(按照URL長度)
mux.es = appendSorted(mux.es, e)
}
if pattern[0] != '/' {
mux.hosts = true
}
//註冊路由完畢,開始返回
}
接下來是 http.ListenAndServe函數
//ListenAndServer函數用來監聽Tcp網路地址並且接下來會呼叫該地址
//使用處理程式來處理傳入上傳連線的請求
//被接收的連線會被設定爲TCP保持有效
//當使用預設的DefaultServerMux時,處理常式預設爲空
// ListenAndServe always returns a non-nil error.
func ListenAndServe(addr string, handler Handler) error {
server := &Server{Addr: addr, Handler: handler}
return 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.
//
// ListenAndServe always returns a non-nil error. After Shutdown or Close,
// the returned error is ErrServerClosed.
func (srv *Server) ListenAndServe() error {
...省略判斷連線關閉或地址爲空的邏輯的邏輯
//監聽該地址
ln, err := net.Listen("tcp", addr)
if err != nil {
return err
}
//處理請求
return srv.Serve(ln)
}
省略其中一大串花裏胡哨的解析包裝呼叫跳轉之後,我們來到了最終的目的地
func (srv *Server) Serve(l net.Listener) error {
for {
//程式會阻塞在這直到有請求過來
rw, err := l.Accept()
...省略花裏胡哨的錯誤處理邏輯
c := srv.newConn(rw)
c.setState(c.rwc, StateNew) // before Serve can return
//最後使用處理連線請求。因爲每一個連線都開起了一個協程,請求的上下文都不同,同時又保證了go的高併發
//serve太長了就不貼了
go c.serve(connCtx)
}
}
// Create new connection from rwc.
func (srv *Server) newConn(rwc net.Conn) *conn {
c := &conn{
// server is the server on which the connection arrived.
// Immutable; never nil.
server: srv,
// rwc is the underlying network connection.
// This is never wrapped by other types and is the value given out
// to CloseNotifier callers. It is usually of type *net.TCPConn or
// *tls.Conn.
rwc: rwc,
}
if debugServerConnections {
c.rwc = newLoggingConn("server", c.rwc)
}
return c
}
最後歡迎大家給我提建議
(本人思維比較混亂…