You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Go中net.Conn.Write返回错误类型及正确写入循环实现问题

Go net.Conn.Write() 常见问题解答

错误判断规则

net.Conn 严格遵守Go标准库的io.Writer接口约定:

If Write returns n < len(p), it must return a non-nil error.

也就是说:只要返回的写入字节数n小于待写入切片的长度,必然同时返回非空错误;反之如果返回错误为nil,则n一定等于len(p)。所以你不需要单独判断n < len(p),所有写入异常都可以通过判断返回的error捕获。

存在会导致n < len(p)的不可恢复错误,常见的包括连接被重置(ECONNRESET)、对端主动关闭连接(EPIPE)等,这类错误出现后无需重试,直接终止写入即可。


错误类型区分方法

使用Go标准库的errors.As、errors.Is做错误判定即可:

  • 先判断是否为网络错误:var netErr net.Error; if errors.As(err, &netErr)
    • 如果netErr.Timeout()返回true:属于超时错误,是可重试的临时错误
    • 如果netErr.Temporary()返回true:属于其他临时网络异常,可重试
    • 其余网络错误均为不可恢复错误,直接终止流程即可
  • 非网络错误一般都属于不可恢复错误,直接终止流程即可

大体积数据的正确写入循环写法

有两种常用实现方案:

  1. 直接调用标准库io.Copy,它已经内置了符合约定的写入重试逻辑,无需自己实现循环:
// 示例:将本地文件内容写入net.Conn
written, err := io.Copy(conn, localFile)
  1. 如需自定义业务逻辑,可以自己实现写入循环:
import (
    "errors"
    "net"
    "time"
)

func writeAll(conn net.Conn, buf []byte) error {
    offset := 0
    for offset < len(buf) {
        n, err := conn.Write(buf[offset:])
        offset += n
        if err != nil {
            // 临时错误重试逻辑,可根据业务需求调整
            var netErr net.Error
            if errors.As(err, &netErr) && netErr.Temporary() {
                // 加短暂休眠避免重试风暴
                time.Sleep(10 * time.Millisecond)
                continue
            }
            return err
        }
    }
    return nil
}

缓冲区满的行为说明

默认情况下net.Conn使用阻塞IO模式:如果内核发送缓冲区已满,Write调用会直接阻塞,直到有足够空间写入所有数据、或者触发超时/网络错误,不会出现“写了部分数据但没返回错误”的情况,符合io.Writer的约定,不会导致边界检查多余。

只有你主动通过SetWriteDeadline设置了写超时的情况下,才会出现写入中途超时、返回部分写入字节和超时错误的情况,按上面的循环逻辑处理即可。


内容的提问来源于stack exchange,提问作者Daniel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 20:06:03