net包 listen

在前面我們簡單的瞭解了一下,如何構建客戶端請求,同時簡單的瞭解了他們之間的調用和封裝關係。從而在封裝方法在滿足不了需求時,我們可以使用更底層一級的方法構建自己的需求。

今天我們看一下服務端的一些監聽方法,在go中監聽方法大致有

 http.ListenAndServeTLS()

http.ListenAndServe()

net.Listen()

net.ListenPacket()

net.ListenTcp()

net.ListenUnix()

net.ListenUdp()

net.ListenIp()

net.ListenUnixgram()

net.ListenMulticastUDP()

讓我們通過一張圖來看看他們之間的關係:


net包 listen - golang




由圖可以看出,http的監聽是對net.Listen()的封裝,而net.Listen()是對Tcp和Unix的封裝。而http的監聽傳入的都是tcp。所有http的監聽最終都是實現的net.ListenTcp()。

其中 net.ListenTcp,net.ListenUdp(),net.ListenIP() 最終走的都是 internetSocket ()。

下面先讓我們看一段代碼:

func (sl *sysListener) listenTCP(ctx context.Context, laddr *TCPAddr) (*TCPListener, error) {

\tfd, err := internetSocket(ctx, sl.network, laddr, nil, syscall.SOCK_STREAM, 0, "listen", sl.ListenConfig.Control)

\tif err != nil {

\t\treturn nil, err

\t}

\treturn &TCPListener{fd}, nil

}


func (sd *sysDialer) doDialTCP(ctx context.Context, laddr, raddr *TCPAddr) (*TCPConn, error) {

\tfd, err := internetSocket(ctx, sd.network, laddr, raddr, syscall.SOCK_STREAM, 0, "dial", sd.Dialer.Control)



\tfor i := 0; i < 2 && (laddr == nil || laddr.Port == 0) && (selfConnect(fd, err) || spuriousENOTAVAIL(err)); i++ {

\t\tif err == nil {

\t\t\tfd.Close()


\t\t}

\t\tfd, err = internetSocket(ctx, sd.network, laddr, raddr, syscall.SOCK_STREAM, 0, "dial", sd.Dialer.Control)

\t}



\tif err != nil {

\t\treturn nil, err

\t}

\treturn newTCPConn(fd), nil

}

通過代碼對比,調用internetSocket只是傳入了不同的識別符 dial和listen 。同時tcp的dial和listen在邏輯上也有些不同,但是如果你去看udp的dial和listen會發現他們的邏輯完全一樣。

說了這麼多廢話後,讓我們看看如何實現一個服務端,首先是我們最常用的http服務:

http.ListenAndServe(),go的web服務構建很簡單隻需要構建監聽路由,然後調用監聽傳入端口就可以了 :

http.HandleFunc("/", HelloServer)

err := http.ListenAndServe(":8080", nil)

if err != nil {

log.Fatal("ListenAndServe: ", err)


}

http.ListenAndServeTLS和ListenAndServe基本相同,只是需要多傳入2個鑰匙:



http.HandleFunc("/", handler)

http.ListenAndServeTLS(":8081", "server.crt",

"server.key", nil)



對於net.Listen處理起來就要比http的麻煩點,他需要你手動處理客戶端請求和實現服務:



func chkError(err error) {

if err != nil {

log.Fatal(err);

}

}



//單獨處理客戶端的請求

func clientHandle(conn net.Conn) {

defer conn.Close();



conn.Write([]byte("hello " + time.Now().String()));

}



func main() {

//創建一個TCP服務端

tcpaddr, err := net.ResolveTCPAddr("tcp4", "127.0.0.1:8080");

chkError(err);

//監聽端口

tcplisten, err2 := net.ListenTCP("tcp", tcpaddr);

chkError(err2);

//死循環的處理客戶端請求

for {

//等待客戶的連接

conn, err3 := tcplisten.Accept();

//如果有錯誤直接跳過

if err3 != nil {

continue;

}



//通過goroutine來處理用戶的請求

go clientHandle(conn);

}

}


分享到:


相關文章: