亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

go標(biāo)準(zhǔn)庫(kù)net/http服務(wù)端的實(shí)現(xiàn)示例

 更新時(shí)間:2024年07月22日 08:32:57   作者:StarSky-yuan  
go的http標(biāo)準(zhǔn)庫(kù)非常強(qiáng)大,本文主要介紹了go標(biāo)準(zhǔn)庫(kù)net/http服務(wù)端,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

1、http簡(jiǎn)單使用

go的http標(biāo)準(zhǔn)庫(kù)非常強(qiáng)大,調(diào)用了兩個(gè)函數(shù)就能夠?qū)崿F(xiàn)一個(gè)簡(jiǎn)單的http服務(wù):

func HandleFunc(pattern string, handler func(ResponseWriter, *Request))
func ListenAndServe(addr string, handler Handler) error

handleFunc注冊(cè)一個(gè)路由和相應(yīng)的處理函數(shù),第一個(gè)參數(shù)表示注冊(cè)的路由,第二個(gè)參數(shù)表示注冊(cè)路由對(duì)應(yīng)的處理函數(shù);ListenAndServe用來(lái)啟動(dòng)http服務(wù)并監(jiān)聽(tīng),第一個(gè)參數(shù)是服務(wù)器地址,第二個(gè)參數(shù)表示使用的處理器。

下面是用這兩個(gè)函數(shù)實(shí)現(xiàn)的簡(jiǎn)單的http服務(wù):注冊(cè)了一個(gè)“/”路由的處理函數(shù),并在8080端口啟動(dòng)http服務(wù),ListenAndServe第二個(gè)參數(shù)為空表示使用標(biāo)準(zhǔn)庫(kù)默認(rèn)的處理器,也可使用自定義處理器,傳參即可。處理器的概念在下面標(biāo)準(zhǔn)庫(kù)分析中進(jìn)行介紹。

import (
    "net/http"
)


func main() {
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        // TODO
    })


    http.ListenAndServe(":8080", nil)
}

2、http標(biāo)準(zhǔn)庫(kù)分析

根據(jù)上面的兩個(gè)函數(shù)來(lái)對(duì)http標(biāo)準(zhǔn)庫(kù)展開(kāi)分析

2.1、服務(wù)端數(shù)據(jù)結(jié)構(gòu)

首先介紹下這兩個(gè)函數(shù)涉及到的數(shù)據(jù)類(lèi)型

(1)服務(wù)器對(duì)象,其中最核心的是Handler成員,表示整個(gè)http服務(wù)的路由器,存儲(chǔ)路由路徑對(duì)應(yīng)到處理函數(shù)的映射,可自定義,例如第1小姐中的案例,沒(méi)有自定義路由器對(duì)象,就會(huì)使用標(biāo)準(zhǔn)庫(kù)提供的默認(rèn)對(duì)象DefaultServeMux

type Server struct {
	Addr string // 地址  host:port
	Handler Handler // 處理器對(duì)象或路由器
    // ...
}

(2)Handler是一個(gè)接口,提供了ServeHTTP方法,用來(lái)將路由映射到相應(yīng)的處理函數(shù)上

type Handler interface {
	ServeHTTP(ResponseWriter, *Request)
}

(3)路由器對(duì)象ServeMux,用來(lái)存儲(chǔ)路由到處理函數(shù)的映射關(guān)系,該對(duì)象就是Handler接口的具體實(shí)現(xiàn)。

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
}

(4)muxEntry就是一個(gè)映射關(guān)系單元

type muxEntry struct {
	h       Handler
	pattern string
}

2.2、HandleFunc流程

http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
    // TODO
})

根據(jù)上面的函數(shù)來(lái)分析標(biāo)準(zhǔn)庫(kù)的執(zhí)行流程,首先看HandleFunc相關(guān)的實(shí)現(xiàn):使用默認(rèn)的DefaultServeMux路由器對(duì)象,調(diào)用ServeMux的HandleFunc,最后路由的注冊(cè)是在mux.handle中實(shí)現(xiàn),其中mux.Handle(pattern, HandlerFunc(handler))中對(duì)處理器做了類(lèi)型轉(zhuǎn)換,HandlerFunc 類(lèi)型實(shí)現(xiàn)了ServeHTTP方法,所以被該類(lèi)型轉(zhuǎn)換后的函數(shù)都是Handler對(duì)象的實(shí)例

var DefaultServeMux = &defaultServeMux

var defaultServeMux ServeMux

type HandlerFunc func(ResponseWriter, *Request)

func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
	f(w, r)
}

func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
    DefaultServeMux.HandleFunc(pattern, handler)
}

func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
	if handler == nil {
		panic("http: nil handler")
	}
	mux.Handle(pattern, HandlerFunc(handler))
}

func (mux *ServeMux) Handle(pattern string, handler Handler) {
	mux.handle(pattern, handler)
}

進(jìn)入到mux.handle中,會(huì)創(chuàng)建一個(gè)路由單元muxEntry對(duì)象,存儲(chǔ)相應(yīng)的路由和處理函數(shù),其中對(duì)于根路徑的存儲(chǔ)需要做出特殊處理,在muxEntry中通過(guò)es存儲(chǔ),并按照順序存儲(chǔ)在muxEntry切片中,到此,已經(jīng)完成了路由注冊(cè)

func (mux *ServeMux) handle(pattern string, handler Handler) {
	mux.mu.Lock()
	defer mux.mu.Unlock()

	if pattern == "" {
		panic("http: invalid pattern")
	}
	if handler == nil {
		panic("http: nil handler")
	}
	if _, exist := mux.m[pattern]; exist {
		panic("http: multiple registrations for " + pattern)
	}

	if mux.m == nil {
		mux.m = make(map[string]muxEntry)
	}
	e := muxEntry{h: handler, pattern: pattern}
	mux.m[pattern] = e
	if pattern[len(pattern)-1] == '/' {
		mux.es = appendSorted(mux.es, e)
	}

	if pattern[0] != '/' {
		mux.hosts = true
	}
}

func appendSorted(es []muxEntry, e muxEntry) []muxEntry {
	n := len(es)
	i := sort.Search(n, func(i int) bool {
		return len(es[i].pattern) < len(e.pattern)
	})
	if i == n {
		return append(es, e)
	}

	es = append(es, muxEntry{}) 
	copy(es[i+1:], es[i:])      
	es[i] = e
	return es
}

2.3、ListenAndServe流程

ListenAndServe先初始化一個(gè)Server對(duì)象,并綁定地址和路由器,調(diào)用Server的ListenAndServe方法,其中net.Listen("tcp", addr)用于創(chuàng)建一個(gè)監(jiān)聽(tīng)套接字并開(kāi)始監(jiān)聽(tīng)指定網(wǎng)絡(luò)地址上的連接,返回一個(gè)實(shí)現(xiàn)了Listener接口的對(duì)象。關(guān)鍵是srv.Serve()

func ListenAndServe(addr string, handler Handler) error {
	server := &Server{Addr: addr, Handler: handler}
	return server.ListenAndServe()
}

func (srv *Server) ListenAndServe() error {
	if srv.shuttingDown() {
		return ErrServerClosed
	}
	addr := srv.Addr
	if addr == "" {
		addr = ":http"
	}
	ln, err := net.Listen("tcp", addr)
	if err != nil {
		return err
	}
	return srv.Serve(ln)
}

在srv.Serve(ln)中使用onceCloseListener 對(duì)Listener進(jìn)行封裝,防止被多次關(guān)閉,context.WithValue用來(lái)將srv服務(wù)器對(duì)象信息存儲(chǔ)在context中,并使用for循環(huán)輪詢等待連接,l.Accept()會(huì)阻塞等待,直到連接到達(dá),并執(zhí)行conn.serve函數(shù)。

type onceCloseListener struct {
	net.Listener
	once     sync.Once
	closeErr error
}

type contextKey struct {
	name string
}

ServerContextKey = &contextKey{"http-server"}

func (srv *Server) Serve(l net.Listener) error {
	l = &onceCloseListener{Listener: l}
	defer l.Close()
    // ...
	ctx := context.WithValue(baseCtx, ServerContextKey, srv)
	for {
		rw, err := l.Accept()
        // ...
		connCtx := ctx
        // ...
		c := srv.newConn(rw)
        // ...
		go c.serve(connCtx)
	}
}

其中newConn會(huì)將Accept的返回的net.Conn封裝成一個(gè)conn對(duì)象,對(duì)每個(gè)請(qǐng)求都會(huì)創(chuàng)建一個(gè)線程來(lái)處理,在conn.serve中會(huì)針對(duì)conn對(duì)象創(chuàng)建讀寫(xiě)器并將內(nèi)容置入緩沖區(qū),在for中調(diào)用readRequest函數(shù)傳入上下文,在readRequest中讀取請(qǐng)求體req,并返回一個(gè)ResponseWriter的接口對(duì)象,用于向請(qǐng)求方返回響應(yīng),并在調(diào)用serverHandler的ServeHTTP方法

type conn struct {
	server *Server
	rwc net.Conn
    // ...
}

func (c *conn) serve(ctx context.Context) {
	c.remoteAddr = c.rwc.RemoteAddr().String()

	ctx = context.WithValue(ctx, LocalAddrContextKey, c.rwc.LocalAddr())
	ctx, cancelCtx := context.WithCancel(ctx)
	c.cancelCtx = cancelCtx
	defer cancelCtx()

	c.r = &connReader{conn: c}
	c.bufr = newBufioReader(c.r)
	c.bufw = newBufioWriterSize(checkConnErrorWriter{c}, 4<<10)

	for {
		w, _ := c.readRequest(ctx)
		serverHandler{c.server}.ServeHTTP(w, w.req)
		w.finishRequest()
		...
	}
}

serverHandler的ServeHTTP方法用來(lái)根據(jù)路由分配handler,如果Server的Handler為空就是用默認(rèn)的DefaultServerMux,對(duì)應(yīng)上了文章一開(kāi)始調(diào)用ListenAndServe的第二個(gè)參數(shù),如果為空就使用默認(rèn)路由器對(duì)象,最后調(diào)用路由器的ServeHTTP函數(shù)。

type serverHandler struct {
	srv *Server
}

func (sh serverHandler) ServeHTTP(rw ResponseWriter, req *Request) {
	handler := sh.srv.Handler
	if handler == nil {
		handler = DefaultServeMux
	}
	if !sh.srv.DisableGeneralOptionsHandler && req.RequestURI == "*" && req.Method == "OPTIONS" {
		handler = globalOptionsHandler{}
	}

	handler.ServeHTTP(rw, req)
}

接下來(lái)流程如下,依次調(diào)用返回命中的handler,如果沒(méi)有命中,則采用模糊匹配命中,最后調(diào)用handler的ServeHTTP函數(shù),因?yàn)樽?cè)路由時(shí)候的函數(shù)在注冊(cè)時(shí)候被強(qiáng)轉(zhuǎn)成HandleFunc函數(shù)類(lèi)型,該類(lèi)型是實(shí)現(xiàn)ServeHTTP方法的,所以執(zhí)行handler的ServeHTTP方法就是執(zhí)行注冊(cè)路由是對(duì)應(yīng)的處理函數(shù)。

func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) {
    h, _ := mux.Handler(r)
    h.ServeHTTP(w, r)
}


func (mux *ServeMux) Handler(r *Request) (h Handler, pattern string) {
    // ...
    return mux.handler(host, r.URL.Path)
}

func (mux *ServeMux) handler(host, path string) (h Handler, pattern string) {
	mux.mu.RLock()
	defer mux.mu.RUnlock()

    return mux.match(path)
}

func (mux *ServeMux) match(path string) (h Handler, pattern string) {
	v, ok := mux.m[path]
	if ok {
		return v.h, v.pattern
	}

	for _, e := range mux.es {
		if strings.HasPrefix(path, e.pattern) {
			return e.h, e.pattern
		}
	}
	return nil, ""
}

到此這篇關(guān)于go標(biāo)準(zhǔn)庫(kù)net/http服務(wù)端的實(shí)現(xiàn)示例的文章就介紹到這了,更多相關(guān)go net/http服務(wù)端內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家! 

相關(guān)文章

  • Golang中的同步工具sync.WaitGroup詳解

    Golang中的同步工具sync.WaitGroup詳解

    這篇文章主要詳細(xì)為大家介紹了Golang中的同步工具sync.WaitGroup,文中有詳細(xì)的代碼示例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,一起跟隨小編過(guò)來(lái)看看吧
    2023-05-05
  • go語(yǔ)言beego框架web開(kāi)發(fā)語(yǔ)法筆記示例

    go語(yǔ)言beego框架web開(kāi)發(fā)語(yǔ)法筆記示例

    這篇文章主要為大家介紹了go語(yǔ)言beego框架web開(kāi)發(fā)語(yǔ)法筆記示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪
    2022-04-04
  • Go語(yǔ)言如何實(shí)現(xiàn)Benchmark函數(shù)

    Go語(yǔ)言如何實(shí)現(xiàn)Benchmark函數(shù)

    go想要在main函數(shù)中測(cè)試benchmark會(huì)麻煩一些,所以這篇文章主要為大家介紹了如何實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的且沒(méi)有開(kāi)銷(xiāo)的benchmark函數(shù),希望對(duì)大家有所幫助
    2024-12-12
  • Golang實(shí)現(xiàn)異步上傳文件支持進(jìn)度條查詢的方法

    Golang實(shí)現(xiàn)異步上傳文件支持進(jìn)度條查詢的方法

    這篇文章主要介紹了Golang實(shí)現(xiàn)異步上傳文件支持進(jìn)度條查詢的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-10-10
  • Go語(yǔ)言異常處理error、panic、recover的使用

    Go語(yǔ)言異常處理error、panic、recover的使用

    GO語(yǔ)言中引入的異常的處理方式為error、panic、recover ,本文主要介紹了Go語(yǔ)言異常處理error、panic、recover的使用,感興趣的可以了解一下
    2024-08-08
  • Go垃圾回收提升內(nèi)存管理效率優(yōu)化最佳實(shí)踐

    Go垃圾回收提升內(nèi)存管理效率優(yōu)化最佳實(shí)踐

    這篇文章主要為大家介紹了Go垃圾回收提升內(nèi)存管理效率優(yōu)化最佳實(shí)踐,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-12-12
  • Go語(yǔ)言并發(fā)編程之互斥鎖Mutex和讀寫(xiě)鎖RWMutex

    Go語(yǔ)言并發(fā)編程之互斥鎖Mutex和讀寫(xiě)鎖RWMutex

    Go 語(yǔ)言中提供了很多同步工具,本文將介紹互斥鎖Mutex和讀寫(xiě)鎖RWMutex的使用方法,想要具體了解的小伙伴,請(qǐng)參考下面文章詳細(xì)內(nèi)容,希望對(duì)你有所幫助
    2021-10-10
  • Go語(yǔ)言編譯原理之源碼調(diào)試

    Go語(yǔ)言編譯原理之源碼調(diào)試

    這篇文章主要為大家介紹了Go語(yǔ)言編譯原理之源碼調(diào)試示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-08-08
  • golang 阻止主goroutine退出的操作

    golang 阻止主goroutine退出的操作

    這篇文章主要介紹了golang 阻止主goroutine退出的操作方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2021-04-04
  • golang雙指針快速排序的實(shí)現(xiàn)代碼

    golang雙指針快速排序的實(shí)現(xiàn)代碼

    這篇文章主要介紹了golang雙指針快速排序的實(shí)現(xiàn)代碼,通過(guò)實(shí)例代碼補(bǔ)充介紹了Golang實(shí)現(xiàn)快速排序和歸并排序以及堆排序算法全注釋,需要的朋友可以參考下
    2024-03-03

最新評(píng)論