在Golang网络编程中,TCP连接的建立与关闭是开发服务端和客户端程序必须掌握的基础流程。标准库net包对这些操作做了良好的封装,使开发者可以用统一的方式处理不同平台的网络交互。

TCP连接的建立流程
客户端通常使用net.Dial或net.DialTCP来主动发起连接,底层会完成三次握手。服务端则通过net.Listen监听端口,并调用Accept接收新连接。
客户端建立连接示例
package main
import (
"fmt"
"net"
)
func main() {
// 发起TCP连接,底层完成三次握手
conn, err := net.Dial("tcp", "127.0.0.1:8080")
if err != nil {
fmt.Println("连接失败:", err)
return
}
defer conn.Close()
fmt.Println("连接已建立:", conn.RemoteAddr())
}
服务端接收连接示例
package main
import (
"fmt"
"net"
)
func main() {
// 监听TCP端口
listener, err := net.Listen("tcp", "127.0.0.1:8080")
if err != nil {
fmt.Println("监听失败:", err)
return
}
defer listener.Close()
for {
// 接收客户端连接
conn, err := listener.Accept()
if err != nil {
fmt.Println("接收失败:", err)
continue
}
fmt.Println("新连接来自:", conn.RemoteAddr())
go handleConn(conn)
}
}
func handleConn(conn net.Conn) {
defer conn.Close()
// 处理读写逻辑
}
数据传输阶段
连接建立后,两端都拿到了net.Conn接口实例,它同时实现了Reader和Writer。可以调用Read和Write方法进行通信。
// 向连接写入数据
_, err := conn.Write([]byte("hello"))
if err != nil {
fmt.Println("写入失败:", err)
}
// 从连接读取数据
buf := make([]byte, 1024)
n, err := conn.Read(buf)
if err != nil {
fmt.Println("读取失败:", err)
}
fmt.Println("收到:", string(buf[:n]))
TCP连接的关闭流程
关闭连接时,应调用conn.Close释放文件描述符。Close会触发四次挥手,若需半关闭可先用CloseWrite关闭写端。
正常关闭示例
// 主动关闭连接
err := conn.Close()
if err != nil {
fmt.Println("关闭失败:", err)
}
半关闭写端示例
// 仅关闭写端,仍可读取对端数据
if tcpConn, ok := conn.(*net.TCPConn); ok {
err := tcpConn.CloseWrite()
if err != nil {
fmt.Println("关闭写端失败:", err)
}
}
注意事项
- 务必使用defer或显式调用Close,避免连接泄漏。
- 并发处理连接时要注意对共享资源的同步。
- 读操作返回EOF表示对端已关闭连接。
理解Golang中TCP从建立到关闭的完整生命周期,是编写健壮网络服务的前提。