引入
Go 文件操作 处理的是本地数据,但现代应用大多需要网络通信。Go 的 net 包封装了 TCP、UDP 等底层协议,配合 http 包 还能处理 HTTP,让 Go 写网络程序既简单又高效。
正文
定义
定义
net包提供底层网络编程功能,包括 TCP 和 UDP 的监听、连接、读写。核心类型是net.Conn(连接)和net.Listener(监听器),它们实现了io.Reader和io.Writer接口,网络数据可以像文件一样读写。
语法
import "net"
// TCP 服务器
listener, err := net.Listen("tcp", ":8080")
conn, err := listener.Accept()
// TCP 客户端
conn, err := net.Dial("tcp", "localhost:8080")
// UDP
addr, err := net.ResolveUDPAddr("udp", ":8080")
conn, err := net.ListenUDP("udp", addr)例子
TCP 服务器
package main
import (
"fmt"
"net"
)
func main() {
listener, err := net.Listen("tcp", ":8080")
if err != nil {
fmt.Println("监听失败:", err)
return
}
defer listener.Close()
for {
conn, err := listener.Accept()
if err != nil {
continue
}
go handleConn(conn)
}
}
func handleConn(conn net.Conn) {
defer conn.Close()
buf := make([]byte, 1024)
n, err := conn.Read(buf)
if err != nil {
return
}
fmt.Println("收到:", string(buf[:n]))
conn.Write([]byte("已收到"))
}net.Listen 在指定端口监听,Accept 阻塞等待客户端连接。每个连接开一个 goroutine 处理,这是 Go 并发服务器的标准写法。
TCP 客户端
conn, err := net.Dial("tcp", "localhost:8080")
if err != nil {
log.Fatal(err)
}
defer conn.Close()
conn.Write([]byte("hello server"))
buf := make([]byte, 1024)
n, _ := conn.Read(buf)
fmt.Println("服务器回复:", string(buf[:n]))net.Dial 连接到服务器,返回 net.Conn。Write 发送数据,Read 接收数据。用法和读写文件一样。
TCP 并发服务器
func handleConn(conn net.Conn) {
defer conn.Close()
scanner := bufio.NewScanner(conn)
for scanner.Scan() {
msg := scanner.Text()
fmt.Println("收到:", msg)
conn.Write([]byte("echo: " + msg + "\n"))
}
}用 bufio.NewScanner 包装 net.Conn,就能按行读取客户端消息。net.Conn 实现了 io.Reader,所以所有读 Reader 的函数都能用。
UDP 服务器
addr, _ := net.ResolveUDPAddr("udp", ":8080")
conn, _ := net.ListenUDP("udp", addr)
defer conn.Close()
buf := make([]byte, 1024)
for {
n, clientAddr, _ := conn.ReadFromUDP(buf)
fmt.Println("收到:", string(buf[:n]), "来自:", clientAddr)
conn.WriteToUDP([]byte("收到"), clientAddr)
}UDP 是无连接协议,不需要 Accept。ReadFromUDP 同时读取数据和发送方地址,WriteToUDP 向指定地址发送数据。
UDP 客户端
addr, _ := net.ResolveUDPAddr("udp", "localhost:8080")
conn, _ := net.DialUDP("udp", nil, addr)
defer conn.Close()
conn.Write([]byte("hello"))
buf := make([]byte, 1024)
n, _ := conn.Read(buf)
fmt.Println("收到:", string(buf[:n]))UDP 客户端用 DialUDP 连接到服务器后,可以像 TCP 一样用 Write / Read。
HTTP 服务器(底层 net 包)
listener, _ := net.Listen("tcp", ":8080")
defer listener.Close()
for {
conn, _ := listener.Accept()
go func(c net.Conn) {
defer c.Close()
c.Write([]byte("HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\nhello"))
}(conn)
}HTTP 本质上是 TCP + 文本协议。直接用 net 包也能写 HTTP 服务器,但一般用 http 包 更方便。
net.Dial 超时
conn, err := net.DialTimeout("tcp", "localhost:8080", 5*time.Second)
if err != nil {
log.Fatal("连接超时:", err)
}
defer conn.Close()DialTimeout 设置连接超时,避免一直阻塞等待。生产环境必须设超时。
常见写法
| 写法 | 说明 |
|---|---|
net.Listen("tcp", addr) | TCP 监听 |
listener.Accept() | 接受 TCP 连接 |
net.Dial("tcp", addr) | TCP 连接 |
net.DialTimeout(network, addr, timeout) | 带超时的连接 |
conn.Read(buf) / conn.Write(buf) | 读写连接数据 |
net.ResolveUDPAddr("udp", addr) | 解析 UDP 地址 |
net.ListenUDP("udp", addr) | UDP 监听 |
conn.ReadFromUDP(buf) | 读取 UDP 数据和来源地址 |
conn.WriteToUDP(buf, addr) | 向指定地址发送 UDP 数据 |
conn.SetDeadline(t) | 设置读写截止时间 |
特点
net.Conn同时实现io.Reader和io.Writer,网络数据和文件用法一样- TCP 服务器标准模式:
Listen→Accept→ 每个连接开 goroutine - UDP 无连接,
ReadFromUDP/WriteToUDP处理每个数据包的来源地址 net.Dial没有超时,生产环境要用DialTimeout- 设置
conn.SetDeadline可以防止连接永远阻塞 - HTTP 协议建立在 TCP 之上,http 包 是对
net包的高层封装
理解
net 包把网络编程变得很直白:TCP 就是 Listen + Accept + Read/Write,UDP 就是 ReadFrom/WriteTo。net.Conn 实现了 io.Reader 和 io.Writer,所以文件操作的那套函数直接就能用在网络连接上。Go 的并发模型让每个连接一个 goroutine 变得轻松,这就是 Go 网络编程的核心优势。大多数时候直接用 net/http 更省事,但理解底层的 net 包能帮你排查网络问题。
引出
网络编程和 HTTP 服务写好了,怎么验证它们是否正确工作?接下来看 Go 测试,学习 Go 内置的测试框架和编写测试用例的方法。