go 中安全使用 net.conn 需设读写截止时间、检查 io.eof 与异常 err、每连接启独立 goroutine 处理、避免 defer 关闭、udp 用 listenudp/readfromudp+writetoudp、tls 用 tls.listen/tls.dial 替换并校验证书。

Go 的 net.Conn 接口怎么用才不阻塞崩溃
直接调用 conn.Read() 或 conn.Write() 时,如果对端断开或网络异常,容易卡死或 panic。关键不是“怎么连”,而是“怎么安全读写”。
-
Read()返回n, err,必须检查err == io.EOF(正常断连)和err != nil && err != io.EOF(异常) - 避免无超时的阻塞:用
conn.SetReadDeadline()和conn.SetWriteDeadline(),时间点需每次调用前重设 - 不要在单个 goroutine 里混用多次
Read()和Write()—— TCP 是字节流,没有消息边界,得自己定义协议(比如头4字节存长度)
用 net.ListenTCP 写服务端时,为什么 accept 后立即 close 会报 use of closed network connection
常见于没起 goroutine 处理连接,主线程 accept 后直接 conn.Close(),但底层 fd 已被复用或回收。根本原因是连接生命周期管理错位。
- 每个
accept()到的net.Conn必须交给独立 goroutine 处理,哪怕只做一次 echo - 不要在 defer 里关 conn —— defer 在函数 return 时才执行,而 handler 函数可能早已退出,conn 已被外部关闭
- 客户端主动断连时,
Read()返回io.EOF,此时应 break 循环并显式conn.Close(),而不是等函数自然结束
UDP 场景下该选 net.ListenUDP 还是 net.DialUDP
二者用途完全不同:DialUDP 用于客户端发起连接(实际仍是无连接,但绑定本地端口、记录远端地址),ListenUDP 用于服务端监听端口并接收任意来源数据包。
- 服务端收发都用
*UDPConn的ReadFromUDP()和WriteToUDP(),注意后者第二个参数是*UDPAddr,不能传 nil - 客户端用
DialUDP后,可用Write()和Read()(隐式绑定远端),但无法接收非目标地址的数据包 - UDP 没有连接状态,所以不存在“断连”概念,错误通常来自系统资源(如缓冲区满)或地址不可达,
WriteToUDP()可能返回syscall.EHOSTUNREACH
如何让 Go Socket 支持 TLS 而不改业务逻辑
核心是把 tls.Conn 当作 net.Conn 的透明封装 —— 它实现了相同接口,可直接替换。
立即学习“go语言免费学习笔记(深入)”;
- 服务端:用
tls.Listen("tcp", addr, config)替代net.Listen(),后续Accept()返回的已是*tls.Conn - 客户端:用
tls.Dial("tcp", addr, config)替代net.Dial(),返回值可直接传给现有 handler - 务必校验证书:
config.InsecureSkipVerify = false(默认),并设置config.ServerName;否则握手会失败或被中间人攻击 - TLS 握手耗时明显,建议在连接池或长连接场景中复用
*tls.Conn,避免频繁重协商
net.core.rmem_max 可能不够。











