如何使用Golang进行Socket通信_Golang Socket编程与网络协议实现

4次阅读

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

如何使用Golang进行Socket通信_Golang Socket编程与网络协议实现

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 用于服务端监听端口并接收任意来源数据包。

  • 服务端收发都用 *UDPConnReadFromUDP()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,避免频繁重协商

实际写的时候最容易漏掉 deadline 设置和 EOF 判断,这两处一松懈,线上就出现 goroutine 泄露或连接假死。UDP 更要小心地址复用和缓冲区大小,linux 默认 net.core.rmem_max 可能不够。

text=ZqhQzanResources