溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

NSQLookupd 中Main方法的作用是什么

發(fā)布時(shí)間:2021-08-11 14:38:00 來源:億速云 閱讀:168 作者:Leah 欄目:云計(jì)算

NSQLookupd 中Main方法的作用是什么,針對(duì)這個(gè)問題,這篇文章詳細(xì)介紹了相對(duì)應(yīng)的分析和解答,希望可以幫助更多想解決這個(gè)問題的小伙伴找到更簡單易行的方法。

type NSQLookupd struct {

     options      *nsqlookupdOptions     // 命令行參數(shù)

     tcpAddr      *net.TCPAddr     // tcp 端口

     httpAddr     *net.TCPAddr     // http 端口

     tcpListener  net.Listener

     httpListener net.Listener

     waitGroup    util.WaitGroupWrapper

     DB           *RegistrationDB

}



這篇文章分析下 daemon.Main() 執(zhí)行過程



1、創(chuàng)建 context,內(nèi)部只有一個(gè)指向NSQLookupd的指針


context := &Context{l}



2、創(chuàng)建 listener;Listen 方法支持面向流的監(jiān)聽,包括 unix domain stream socket。


tcpListener, err := net.Listen("tcp", l.tcpAddr.String())



3、創(chuàng)建 tcpServer struct,內(nèi)部只含有一個(gè) context 指針,為什么需要對(duì) NSQLookupd


tcpServer 實(shí)現(xiàn)了 Handle(net.Conn) 方法,表明實(shí)現(xiàn)了 TCPHandler 接口


tcpServer := &tcpServer{context: context}



4、分析 l.waitGroup.Wrap(func() { util.TCPServer(tcpListener, tcpServer) })


waitGroup 是結(jié)構(gòu)體 util.WaitGroupWrapper 實(shí)例,此結(jié)構(gòu)體繼承自 sync.WaitGroup;WaitGroup 等待一組協(xié)程結(jié)束。主協(xié)程調(diào)用 Add 方法來設(shè)置等待協(xié)程的數(shù)目;func() { util.TCPServer(tcpListener, tcpServer) } 這是一個(gè)匿名函數(shù)。


總結(jié):主協(xié)程調(diào)用 Wrap 方法,調(diào)用 Add,設(shè)置等待的協(xié)程數(shù)目為1,啟動(dòng)新的協(xié)程去調(diào)用 匿名函數(shù),主協(xié)程最后會(huì)在 exitChan 通道上等待消息,如果收到中斷信號(hào),關(guān)閉 tcpListener, httpListner,最后在 waitGroup 上等待協(xié)程結(jié)束。需要 waitGroup 的目的,就是為了 主協(xié)程 和 監(jiān)聽協(xié)程之間的狀態(tài)同步。



5、監(jiān)聽協(xié)程執(zhí)行的邏輯如下,簡化版本,忽略日志和錯(cuò)誤處理。監(jiān)聽協(xié)程循環(huán) Accept,然后分配新的協(xié)程調(diào)用 handler 處理接收的 clientConn。處理客戶端連接的協(xié)程,我把它叫做 工作協(xié)程。


func TCPServer(listener net.Listener, handler TCPHandler) {


     for {

          clientConn, err := listener.Accept()

          go handler.Handle(clientConn)

     }


}



6、工作協(xié)程的處理邏輯,最終調(diào)用的是 tcpServer 的 Handle 方法,這是最重要的一個(gè)方法,重點(diǎn)分析


func (p *tcpServer) Handle(clientConn net.Conn)


buf := make([]byte, 4)

_, err := io.ReadFull(clientConn, buf)


讀取客戶端發(fā)送過來的前4個(gè)字節(jié),里面含有協(xié)議的版本號(hào)??吹搅藳]有,完全阻塞式編程,沒有屎一樣的事件驅(qū)動(dòng)!


判斷版本號(hào)后,最終調(diào)用 LookupProtocolV1 的 IOLoop 方法



7、方法分析 func (p *LookupProtocolV1) IOLoop(conn net.Conn) error


client := NewClientV1(conn)     // ClientV1 struct 繼承 net.Conn,封裝一個(gè) PeerInfo


reader := bufio.NewReader(client) // 創(chuàng)建一個(gè)帶緩沖的 reader


for {     // 此部分代碼有省略

    line, err = reader.ReadString('\n’)     // 按行來處理


    line = strings.TrimSpace(line)

    params := strings.Split(line, " ")


    response, err := p.Exec(client, reader, params)  // 執(zhí)行命令


    if response != nil {

        _, err = util.SendResponse(client, response)     // 發(fā)送 response

    }

}


IO 出錯(cuò),或者執(zhí)行命令出錯(cuò),會(huì)退出循環(huán)。



8、命令分派


func (p *LookupProtocolV1) Exec(client *ClientV1, reader *bufio.Reader, params []string) ([]byte, error)


switch params[0] {

case "PING":

    return p.PING(client, params)

// .........

}


根據(jù)第一個(gè)參數(shù)做命令區(qū)分,調(diào)用響應(yīng)的指令



9、命令執(zhí)行,以 ping 命令為例,看看命令如何執(zhí)行


func (p *LookupProtocolV1) PING(client *ClientV1, params []string) ([]byte, error)


atomic.StoreInt64(&client.peerInfo.lastUpdate, now.UnixNano()) // 更新客戶端的狀態(tài)


return []byte("OK"), nil      // 返回 “OK”,經(jīng)由第 7 步的 util.SendResponse 發(fā)送給 client


至此 tcpServer 的處理流程就介紹完了。



10、和 2,3 步對(duì)應(yīng)的,還會(huì)創(chuàng)建 httpListener, httpServer, 主要負(fù)責(zé) topic,channel 相關(guān)的操作


httpListener, err := net.Listen("tcp", l.httpAddr.String())

httpServer := &httpServer{context: context}


處理 httpServer 的協(xié)程, 會(huì)調(diào)用 func() { util.HTTPServer(httpListener, httpServer, "HTTP") }



11、分析 util.HTTPServer 函數(shù)


關(guān)鍵是如下兩句

server := &http.Server{

    Handler: handler,

}

err := server.Serve(listener)


默認(rèn)的 http handler 就是 httpServer 本身



12、分析 httpServer 的 ServeHTTP 方法


err := s.v1Router(w, req)     // 路由請(qǐng)求



13、分析 v1Router


switch req.URL.Path {

case "/ping”:

//......

}


按照請(qǐng)求路徑分派



14、以 "/topics” 為例,看如何處理請(qǐng)求


執(zhí)行函數(shù) util.NegotiateAPIResponseWrapper(w, req,

               func() (interface{}, error) { return s.doTopics(req) })

關(guān)于NSQLookupd 中Main方法的作用是什么問題的解答就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關(guān)注億速云行業(yè)資訊頻道了解更多相關(guān)知識(shí)。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI