net
Go 語言的net標准庫是一個非常強大的庫,它提供了處理網絡通信、IP 地址、DNS 解析、TCP/UDP 協議、HTTP 協議等常見任務的功能。由於 Go 語言本身的並發特性,得益於此,Go 在處理網絡 IO 的時候非常的簡潔高效。
地址解析
Go 提供了四個函數來解析網絡地址,下面逐一講解。
MAC 地址
簽名
go
func ParseMAC(s string) (hw HardwareAddr, err error)示例
go
package main
import (
"fmt"
"net"
)
func main() {
hw, err := net.ParseMAC("00:1A:2B:3C:4D:5E")
if err != nil {
panic(err)
}
fmt.Println(hw)
}CIDR
簽名
go
func ParseCIDR(s string) (IP, *IPNet, error)示例
go
package main
import (
"fmt"
"log"
"net"
)
func main() {
ipv4Addr, ipv4Net, err := net.ParseCIDR("192.0.2.1/24")
if err != nil {
log.Fatal(err)
}
fmt.Println(ipv4Addr)
fmt.Println(ipv4Net)
}IP 地址
IP 地址支持解析 ipv4,ipv6,函數簽名如下
go
func ResolveIPAddr(network, address string) (*IPAddr, error)使用示例如下
go
package main
import (
"fmt"
"net"
)
func main() {
ipv4Addr, err := net.ResolveIPAddr("ip4", "192.168.2.1")
if err != nil {
panic(err)
}
fmt.Println(ipv4Addr)
ipv6Addr, err := net.ResolveIPAddr("ip6", "2001:0db8:85a3:0000:0000:8a2e:0370:7334")
if err != nil {
panic(err)
}
fmt.Println(ipv6Addr)
}TCP 地址
TCP 地址支持 tcp4,tcp6,簽名如下
go
func ResolveTCPAddr(network, address string) (*TCPAddr, error)使用示例如下
go
package main
import (
"fmt"
"net"
)
func main() {
tcp4Addr, err := net.ResolveTCPAddr("tcp4", "0.0.0.0:2020")
if err != nil {
panic(err)
}
fmt.Println(tcp4Addr)
tcp6Addr, err := net.ResolveTCPAddr("tcp6", "[::1]:8080")
if err != nil {
panic(err)
}
fmt.Println(tcp6Addr)
}UDP 地址
UDP 地址支持 udp4,udp6,簽名如下
go
func ResolveUDPAddr(network, address string) (*UDPAddr, error)使用示例如下
go
package main
import (
"fmt"
"net"
)
func main() {
udp4Addr, err := net.ResolveUDPAddr("udp4", "0.0.0.0:2020")
if err != nil {
panic(err)
}
fmt.Println(udp4Addr)
udp6Addr, err := net.ResolveUDPAddr("udp6", "[::1]:8080")
if err != nil {
panic(err)
}
fmt.Println(udp6Addr)
}Unix 地址
Unix 地址支持 unix,unixgram,unixpacket,簽名如下
go
func ResolveUnixAddr(network, address string) (*UnixAddr, error)使用示例如下
go
package main
import (
"fmt"
"net"
)
func main() {
unixAddr, err := net.ResolveUnixAddr("unix", "/tmp/mysocket")
if err != nil {
panic(err)
}
fmt.Println(unixAddr)
}DNS
Go 還提供了很多函數用於 DNS 查詢,下面一個例子是解析域名的 IP 地址
go
package main
import (
"fmt"
"net"
)
func main() {
addrs, err := net.LookupHost("github.com")
if err != nil {
panic(err)
}
fmt.Println(addrs)
}查詢記錄值
go
package main
import (
"fmt"
"net"
)
func main() {
mxs, err := net.LookupMX("github.com")
if err != nil {
panic(err)
}
fmt.Println(mxs)
}網絡編程
tcp 編程的邏輯十分簡單,對於客戶端而言就是
- 建立連接
- 發送數據或讀取數據
- 退出
對於服務端而言就是
- 監聽地址
- 獲取連接
- 新建一個協程去處理該連接
下面是一個簡單的例子,客戶端代碼
go
package main
import (
"net"
)
func main() {
// 建立連接
conn, err := net.Dial("tcp", "0.0.0.0:1234")
if err != nil {
panic(err)
}
defer conn.Close()
// 發送數據
for i := range 10 {
_, err := conn.Write([]byte{'a' + byte(i)})
if err != nil {
panic(err)
}
}
}服務端代碼
go
package main
import (
"errors"
"fmt"
"io"
"net"
"sync"
)
func main() {
// 監聽地址
listener, err := net.Listen("tcp", "0.0.0.0:1234")
if err != nil {
panic(err)
}
defer listener.Close()
var wg sync.WaitGroup
for {
// 阻塞等待下一個連接建立
conn, err := listener.Accept()
if err != nil {
panic(err)
}
// 開啟一個新的協程去異步處理該連接
wg.Add(1)
go func() {
defer wg.Done()
buf := make([]byte, 4096)
for {
// 從連接中讀取數據
n, err := conn.Read(buf)
if errors.Is(err, io.EOF) {
break
} else if err != nil {
panic(err)
}
data := string(buf[:n])
fmt.Println(data)
}
}()
}
wg.Wait()
}客戶端發送數據,服務端接收數據,這個例子非常的簡單,服務端建立新連接時,只需開啟一個新的協程就可以去處理,不需要阻塞,UDP 大體上的寫法也都是類似的。
