這篇文章介紹了Golang如何實(shí)現(xiàn)TCP和UDP傳輸,轉(zhuǎn)自Mina Andrawos的Implementing UDP vs TCP in Golang。
Go被稱為可移植的系統(tǒng)編程語(yǔ)言,以其簡(jiǎn)潔的語(yǔ)法、易于部署和良好的性能受到后端程序員的歡迎。網(wǎng)絡(luò)通信是后端服務(wù)軟件的一個(gè)重要功能,目前存在大量的應(yīng)用層的通信協(xié)議能夠滿足這個(gè)功能需求。構(gòu)建這些協(xié)議的技術(shù)基礎(chǔ)或是TCP、或是UDP,在這篇文章將簡(jiǎn)要介紹兩種協(xié)議的Go語(yǔ)言實(shí)現(xiàn)。
TCP IN GO
TCP作為HTTP協(xié)議實(shí)現(xiàn)的底層核心協(xié)議受到了廣泛的關(guān)注,很多文章對(duì)Go語(yǔ)言的TCP支持都有所介紹。下面的內(nèi)容將涉及Go語(yǔ)言中TCP的實(shí)際應(yīng)用。 首先需要導(dǎo)入Go語(yǔ)言的net包,net包中包含了眾多的網(wǎng)絡(luò)通信協(xié)議的支持。關(guān)于TCP協(xié)議的支持涉及到TCPAddr、TCPConn和TCPListener等具體類(lèi)型,如果您有興趣可以進(jìn)行深入研究。 在大多數(shù)應(yīng)用場(chǎng)景中,我們并不需要直接調(diào)用這些類(lèi)型,除非對(duì)網(wǎng)絡(luò)連接有更高的要求。
UDP IN GO
Go語(yǔ)言對(duì)UDP的支持并沒(méi)有像TCP那樣被眾多的博客和論壇關(guān)注。UDP作為一個(gè)重要的傳輸層協(xié)議,是構(gòu)成很多應(yīng)用層軟件協(xié)議的基礎(chǔ)。 net包支持很多關(guān)于UDP協(xié)議的類(lèi)型,包括UDPConn和UDPAddr。許多網(wǎng)絡(luò)上的實(shí)現(xiàn)的例子都是基于這些基礎(chǔ)類(lèi)型直接實(shí)現(xiàn)UDP,然而在Go中還有更優(yōu)雅的方式實(shí)現(xiàn)UDP。 像對(duì)TCP支持一樣,Go也提供了很多抽象接口用于實(shí)現(xiàn)UDP網(wǎng)絡(luò)通信,最為重要的包是PacketConn包。
UDP VS TCP IN GOLANG: CLIENT IMPLEMENTATION
終于到了看代碼的時(shí)候了,如果我們基于接口實(shí)現(xiàn)客戶端,TCP和UDP的實(shí)現(xiàn)方式?jīng)]有什么明顯的區(qū)別。
TCP:
//Connect TCP
conn, err := net.Dial("tcp", "host:port")
if err != nil {
return err
}
defer conn.Close()
//simple Read
buffer := make([]byte, 1024)
conn.Read(buffer)
//simple write
conn.Write([]byte("Hello from client"))
net.Dial()返回Conn接口,接口支持Read和Write方法。 net.Dial()引入了"tcp"參數(shù),說(shuō)明我們將建立一個(gè)tcp連接,我們引入的第二個(gè)參數(shù)作為連接的目標(biāo)地址。 現(xiàn)在來(lái)看一下UDP的實(shí)現(xiàn)代碼:
//Connect udp
conn, err := net.Dial("udp", "host:port")
if err != nil {
return err
}
defer conn.Close()
//simple Read
buffer := make([]byte, 1024)
conn.Read(buffer)
//simple write
conn.Write([]byte("Hello from client"))
相當(dāng)直觀的實(shí)現(xiàn)!唯一的不同就是net.Dial()的第一個(gè)參數(shù),這里的參數(shù)是"udp",表示我們將進(jìn)行一次UDP的連接。
UDP VS TCP IN GOLANG: SERVER IMPLEMENTATION
UDP和TCO服務(wù)端程序的實(shí)現(xiàn)由很大的不同,在TCP場(chǎng)景下,我們需要使用 Listener 接口監(jiān)聽(tīng)和接受TCP連接:
// listen to incoming tcp connections
l, err := net.Listen("tcp", "host:port")
if err != nil {
return err
}
defer l.Close()
// A common pattern is to start a loop to continously accept connections
for {
//accept connections using Listener.Accept()
c, err := l.Accept()
if err!= nil {
return err
}
//It's common to handle accepted connection on different goroutines
go handleConnection(c)
}
代碼簡(jiǎn)單、直觀,只需要理解基本的TCP連接知識(shí):服務(wù)器監(jiān)聽(tīng)連接請(qǐng)求、接受請(qǐng)求、并且通過(guò)讀取或者寫(xiě)入數(shù)據(jù)處理請(qǐng)求。下面我們看一下如何讀取和寫(xiě)入數(shù)據(jù):
func handleConnection(c net.Conn) {
//some code...
//Simple read from connection
buffer := make([]byte, 1024)
c.Read(buffer)
//simple write to connection
c.Write([]byte("Hello from server"))
}
注意Listener.Accept()返回的連接請(qǐng)求也是Conn接口類(lèi)型,這個(gè)跟TCP客戶端返回的數(shù)據(jù)類(lèi)型相同。所以他同樣支持io.Reader和io.Writer方法。 UDP的服務(wù)器實(shí)現(xiàn)基于不同的方式,這里使用PacketConn接口:
// listen to incoming udp packets
pc, err := net.ListenPacket("udp", "host:port")
if err != nil {
log.Fatal(err)
}
defer pc.Close()
//simple read
buffer := make([]byte, 1024)
pc.ReadFrom(buffer)
//simple write
pc.WriteTo([]byte("Hello from client"), addr)
對(duì)于UDP服務(wù)器來(lái)說(shuō),我們調(diào)用net.ListenPacket(),并且引入?yún)?shù)"udp"來(lái)處理UDP連接請(qǐng)求。PacketConn不支持io.reader和io.writer,但是他支持兩個(gè)替代方法ReadFrom()和WriteTo()。 希望這篇文章能夠幫助您開(kāi)啟Go中的TCP和UDP實(shí)現(xiàn)的研究之路。