net
Gói thư viện chuẩn net của Go rất mạnh mẽ, cung cấp các chức năng xử lý truyền thông mạng, địa chỉ IP, phân giải DNS, giao thức TCP/UDP, giao thức HTTP và các tác vụ phổ biến khác. Nhờ đặc tính concurrent của Go, việc xử lý network IO rất gọn nhẹ và hiệu quả.
Phân tích địa chỉ
Go cung cấp bốn hàm để phân tích địa chỉ mạng, dưới đây sẽ giải thích từng cái.
Địa chỉ MAC
Chữ ký
func ParseMAC(s string) (hw HardwareAddr, err error)Ví dụ
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
Chữ ký
func ParseCIDR(s string) (IP, *IPNet, error)Ví dụ
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)
}Địa chỉ IP
Địa chỉ IP hỗ trợ phân tích ipv4, ipv6, chữ ký hàm như sau
func ResolveIPAddr(network, address string) (*IPAddr, error)Sử dụng ví dụ như sau
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)
}Địa chỉ TCP
Địa chỉ TCP hỗ trợ tcp4, tcp6, chữ ký như sau
func ResolveTCPAddr(network, address string) (*TCPAddr, error)Sử dụng ví dụ như sau
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)
}Địa chỉ UDP
Địa chỉ UDP hỗ trợ udp4, udp6, chữ ký như sau
func ResolveUDPAddr(network, address string) (*UDPAddr, error)Sử dụng ví dụ như sau
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)
}Địa chỉ Unix
Địa chỉ Unix hỗ trợ unix, unixgram, unixpacket, chữ ký như sau
func ResolveUnixAddr(network, address string) (*UnixAddr, error)Sử dụng ví dụ như sau
package main
import (
"fmt"
"net"
)
func main() {
unixAddr, err := net.ResolveUnixAddr("unix", "/tmp/mysocket")
if err != nil {
panic(err)
}
fmt.Println(unixAddr)
}DNS
Go còn cung cấp nhiều hàm dùng cho truy vấn DNS, dưới đây là một ví dụ phân tích địa chỉ IP của tên miền
package main
import (
"fmt"
"net"
)
func main() {
addrs, err := net.LookupHost("github.com")
if err != nil {
panic(err)
}
fmt.Println(addrs)
}Truy vấn bản ghi MX
package main
import (
"fmt"
"net"
)
func main() {
mxs, err := net.LookupMX("github.com")
if err != nil {
panic(err)
}
fmt.Println(mxs)
}Lập trình mạng
Logic lập trình tcp rất đơn giản, đối với client là
- Thiết lập kết nối
- Gửi dữ liệu hoặc đọc dữ liệu
- Thoát
Đối với server là
- Lắng nghe địa chỉ
- Lấy kết nối
- Tạo một goroutine mới để xử lý kết nối đó
Dưới đây là một ví dụ đơn giản, code client
package main
import (
"net"
)
func main() {
// Thiết lập kết nối
conn, err := net.Dial("tcp", "0.0.0.0:1234")
if err != nil {
panic(err)
}
defer conn.Close()
// Gửi dữ liệu
for i := range 10 {
_, err := conn.Write([]byte{'a' + byte(i)})
if err != nil {
panic(err)
}
}
}Code server
package main
import (
"errors"
"fmt"
"io"
"net"
"sync"
)
func main() {
// Lắng nghe địa chỉ
listener, err := net.Listen("tcp", "0.0.0.0:1234")
if err != nil {
panic(err)
}
defer listener.Close()
var wg sync.WaitGroup
for {
// Chặn đợi kết nối tiếp theo được thiết lập
conn, err := listener.Accept()
if err != nil {
panic(err)
}
// Khởi tạo một goroutine mới để xử lý kết nối đó một cách bất đồng bộ
wg.Add(1)
go func() {
defer wg.Done()
buf := make([]byte, 4096)
for {
// Đọc dữ liệu từ kết nối
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()
}Client gửi dữ liệu, server nhận dữ liệu, ví dụ này rất đơn giản, khi server thiết lập kết nối mới, chỉ cần khởi tạo một goroutine mới là có thể xử lý, không cần chặn, UDP về cơ bản cũng viết tương tự.
