为了账号安全,请及时绑定邮箱和手机立即绑定

net.Conn.Write 返回什么错误

net.Conn.Write 返回什么错误

Go
慕姐4208626 2022-10-10 19:07:59
根据 go 文档,如果net.Conn.Write()函数无法发送给定切片中的所有字节,它将返回错误。在这种情况下,我如何知道返回了哪种类型的错误?我应该检查是否有错误,如果 n > 0 和 n < len(p) ?或者仅检查 n < len(p) 是否就足够了?是否存在 n < len(p) 的不可恢复错误?例如,假设我想发送 X GB 的数据。“正确”的 Write() 循环会是什么样子?如果输出缓冲区已满,Write() 会阻塞直到它从 p 发送所有内容?检查 n < len(p) 是多余的吗?
查看完整描述

4 回答

?
弑天下

TA贡献1818条经验 获得超8个赞

嗯,net.Conn是一个界面。这意味着完全取决于实现来确定要发送回哪些错误。TCP 连接和 UNIX 套接字连接可能有非常不同的原因导致无法完全完成写入。

签名与net.Conn.Write签名完全相同io.Writer。这意味着每个实现net.Conn也实现io.Writer. 因此,您可以使用任何现有方法,例如io.Copyio.CopyN将数据写入连接。


查看完整回答
反对 回复 2022-10-10
?
一只斗牛犬

TA贡献1784条经验 获得超2个赞

在这种情况下,我如何知道返回了哪种类型的错误?我应该检查是否有错误,如果 n > 0 和 n < len(p) ?

用于n < len(p)检测写入提前停止的情况。在这种情况下,错误不是零。

是否存在 n < len(p) 的不可恢复错误?

是的。写入某些数据后,网络连接可能会失败。

也有可恢复的错误。如果由于超过了写入期限而导致写入失败,则具有新期限的稍后写入可以成功。

例如,假设我想发送 X GB 的数据。“正确”的 Write() 循环会是什么样子?

如果您询问如何将 a 写入[]byte连接,则在大多数情况下不需要循环。在写入数据或发生错误之前,Write 调用会阻塞。使用此代码:

_, err := c.Write(p)

如果您询问如何将 io.Reader 复制到网络连接,请使用_, err := io.Copy(conn, r).

写不同于读。读取可以在填充缓冲区之前返回。

如果输出缓冲区已满,Write() 会阻塞直到它从 p 发送所有内容?

写入阻塞,直到所有数据都发送完毕或写入失败并出现错误(超过最后期限,网络故障,网络连接在其他 goroutine 中关闭,...)。


查看完整回答
反对 回复 2022-10-10
?
qq_花开花谢_0

TA贡献1835条经验 获得超7个赞

因此,我深入研究了 Go 源代码本身。我跟踪了对名为src/internal/poll/fd_unix.go.


// Write implements io.Writer.

func (fd *FD) Write(p []byte) (int, error) {

    if err := fd.writeLock(); err != nil {

        return 0, err

    }

    defer fd.writeUnlock()

    if err := fd.pd.prepareWrite(fd.isFile); err != nil {

        return 0, err

    }

    var nn int

    for {

        max := len(p)

        if fd.IsStream && max-nn > maxRW {

            max = nn + maxRW

        }

        n, err := ignoringEINTRIO(syscall.Write, fd.Sysfd, p[nn:max])

        if n > 0 {

            nn += n

        }

        if nn == len(p) {

            return nn, err

        }

        if err == syscall.EAGAIN && fd.pd.pollable() {

            if err = fd.pd.waitWrite(fd.isFile); err == nil {

                continue

            }

        }

        if err != nil {

            return nn, err

        }

        if n == 0 {

            return nn, io.ErrUnexpectedEOF

        }

    }

}

这似乎已经处理了重传。因此,Write() 实际上确实保证了所有内容都已发送,或者发生了无法恢复的致命错误。


在我看来,除了记录目的之外,根本不需要关心 n 的值。如果曾经发生错误,那么它已经足够严重以至于没有理由尝试重新传输剩余的 len(p)-n 个字节。


查看完整回答
反对 回复 2022-10-10
?
慕田峪7331174

TA贡献1828条经验 获得超13个赞

这net.Conn.Write()是为了实现io.Writer接口,该接口具有以下关于错误的约定:


如果返回 n < len(p),则写入必须返回非零错误。


没有一个正确的写循环。对于某些情况,了解写入了多少数据可能很重要。但是,对于网络连接,基于此合同,以下内容应该有效:


var err error

for data, done := getNextSegment(); !done&&err==nil; data, done = getNextSegment() {

  _,err=conn.Write(data)

}

要保持写入的字节总数:


var err error

written:=0

for data, done := getNextSegment(); !done&&err==nil; data, done = getNextSegment() {

  n,err=conn.Write(data)

  written+=n

}


查看完整回答
反对 回复 2022-10-10
  • 4 回答
  • 0 关注
  • 197 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信