文档结构  
翻译进度:已翻译     翻译赏金:0 元 (?)    ¥ 我要打赏

Go因为作为非常好用的系统编程语言而知名。开发者很喜欢它在开发后端服务时的简洁,易于开发和高性能。在很多后端服务中一个关键的特性是网络通信。有很多应用级别的协议用于软件之间通过网络进行交互。在它们的底层大都依赖于 TCP 或者 UDP。在本文中, 我们将讨论在Golang中实现UDP和TCP所涉及到的一些代码。让我们开始吧。

Go语言中的TCP

在Go语言中支持TCP已经有大量的文章和资源讲解了。显然,因为它作为互联网中广泛使用的HTTP协议的底层协议,使得它变得非常流行。 让我们看看在Go语言中使用TCP的一些实例。

第 1 段(可获 1.68 积分)

首先,最重要的是Go的net包,它是在Go中任何网络通信的关键。在net包中,包含了 TCPAddrTCPConn, and TCPListener 这几个用于支持TCP的数据类型。如果你对此感兴趣,可以花一些时间去研究一下它们。在大多数情况下,除非需要访问连接的高级属性,我们并不需要直接使用这些类型。Go的net包支持一些不仅仅包含TCP,还包含其它的面向流的网络协议,比如TCP, unix或者unixpocket。这些接口是 Conn 和 Listener,我们将会简短的了解一下这两个接口。

第 2 段(可获 1.45 积分)

Go语言中的UDP

在Go语言中,UDP的支持并不像TCP那样在很多博客和论坛中有很多指南。对于现代软件来说,UDP是非常重要的协议,有些情况下使用UDP作为我们的网络协议是非常合理的。

Go的net包提供了对UDP相关类型的支持,主要包含 UDPConn 和 UDPAddr。在网络上我找到的大部分例子都是直接使用这些类型,但是,在Go中有更好的方式去开发基于UDP的软件。

与TCP一样,也有很多抽象的接口用于使用UDP进行通信。最重要的是 PacketConn,它提供了对面向数据报的协议如UDP,IP或者Unix数据报的支持。 

第 3 段(可获 1.46 积分)

Go 语言的 UDP 和 TCP 客户端实现

现在我们开始来看看实际的代码,如果我们使用接口,那么 TCP 和 UDP 版本的实现是一致的,来看看具体代码:

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 接口,支持读和写方法。Conn 支持超级受欢迎的 io.Reader 和 io.Writer 接口,在 Go 的很多包中都有实现,例如 bufio 允许缓冲 I/O 读写。

第 4 段(可获 1.04 积分)

我们注意到net.Dial()有一个“tcp”的字符串参数,它用于告诉Go初始化一个tcp连接。第二个参数是目标地址。

那关于UDP客户端怎么写?猜一下!!

//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"))

非常直接对吧?唯一的不同是net.Dial()函数的第一个参数不同。我们使用“udp”表明我们希望创建一个UDP连接。

第 5 段(可获 0.9 积分)

GOLANG中的TCP VS UDP:服务端实现

TCP和UDP在服务端的实现是不同的。在实现TCP的时候,我们需要使用 Listener 接口 监听和接受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)
}
第 6 段(可获 0.51 积分)

代码是非常简单和直接的,只需要对TCP服务端有一些基础的理解:你需要监听来自外部的连接,然后通过在连接上读写数据处理对它进行处理。让我们看一段关于如何读写数据的最简单的代码:

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()返回的连接是与TCP客户端一样的,都实现了 Conn 接口。对io.Reader和io.Writer的支持使它可以在很多Go的包中得到很好地兼容。

第 7 段(可获 1.25 积分)

在Go中实现一个UDP服务器与TCP有些不同,它使用 PacketConn 接口取代了Conn接口和listener。让我们看一下如何实现:

// 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)

对于UDP服务器来说,我们使用net.ListenPacket()方法,加上"udp"参数宣称我们准备在服务器的地址上接收UDP交互。我们之后就可以对UDP客户端进行读写了。
与类型Conn不同的是,PackerConn并不支持io.reader和io.writer接口,但是它支持两个特殊的读写方法ReadFrom() 和 WriteTo() 。WriteTo()方法需要提供一个参数作为发送的数据到哪个地址,ReadFrom()则返回数据是从哪个地址接收的。

本文应该可以作为在Go中实现TCP和UDP的代码实践,希望你能够学到一些新的东西。

第 8 段(可获 1.79 积分)

文章评论