net.Conn.Write 返回什么错误

根据 go 文档,如果net.Conn.Write()函数无法发送给定切片中的所有字节,它将返回错误。

在这种情况下,我如何知道返回了哪种类型的错误?我应该检查是否有错误,如果 n > 0 和 n < len(p) ?或者仅检查 n < len(p) 是否就足够了?是否存在 n < len(p) 的不可恢复错误?

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

如果输出缓冲区已满,Write() 会阻塞直到它从 p 发送所有内容?检查 n < len(p) 是多余的吗?


慕姐4208626
浏览 201回答 4
4回答

弑天下

嗯,net.Conn是一个界面。这意味着完全取决于实现来确定要发送回哪些错误。TCP 连接和 UNIX 套接字连接可能有非常不同的原因导致无法完全完成写入。签名与net.Conn.Write签名完全相同io.Writer。这意味着每个实现net.Conn也实现io.Writer.&nbsp;因此,您可以使用任何现有方法,例如io.Copy或io.CopyN将数据写入连接。

一只斗牛犬

在这种情况下,我如何知道返回了哪种类型的错误?我应该检查是否有错误,如果 n > 0 和 n < len(p) ?用于n < len(p)检测写入提前停止的情况。在这种情况下,错误不是零。是否存在 n < len(p) 的不可恢复错误?是的。写入某些数据后,网络连接可能会失败。也有可恢复的错误。如果由于超过了写入期限而导致写入失败,则具有新期限的稍后写入可以成功。例如,假设我想发送 X GB 的数据。“正确”的 Write() 循环会是什么样子?如果您询问如何将 a 写入[]byte连接,则在大多数情况下不需要循环。在写入数据或发生错误之前,Write 调用会阻塞。使用此代码:_,&nbsp;err&nbsp;:=&nbsp;c.Write(p)如果您询问如何将 io.Reader 复制到网络连接,请使用_, err := io.Copy(conn, r).写不同于读。读取可以在填充缓冲区之前返回。如果输出缓冲区已满,Write() 会阻塞直到它从 p 发送所有内容?写入阻塞,直到所有数据都发送完毕或写入失败并出现错误(超过最后期限,网络故障,网络连接在其他 goroutine 中关闭,...)。

qq_花开花谢_0

因此,我深入研究了 Go 源代码本身。我跟踪了对名为src/internal/poll/fd_unix.go.// Write implements io.Writer.func (fd *FD) Write(p []byte) (int, error) {&nbsp; &nbsp; if err := fd.writeLock(); err != nil {&nbsp; &nbsp; &nbsp; &nbsp; return 0, err&nbsp; &nbsp; }&nbsp; &nbsp; defer fd.writeUnlock()&nbsp; &nbsp; if err := fd.pd.prepareWrite(fd.isFile); err != nil {&nbsp; &nbsp; &nbsp; &nbsp; return 0, err&nbsp; &nbsp; }&nbsp; &nbsp; var nn int&nbsp; &nbsp; for {&nbsp; &nbsp; &nbsp; &nbsp; max := len(p)&nbsp; &nbsp; &nbsp; &nbsp; if fd.IsStream && max-nn > maxRW {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; max = nn + maxRW&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; n, err := ignoringEINTRIO(syscall.Write, fd.Sysfd, p[nn:max])&nbsp; &nbsp; &nbsp; &nbsp; if n > 0 {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; nn += n&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; if nn == len(p) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return nn, err&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; if err == syscall.EAGAIN && fd.pd.pollable() {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if err = fd.pd.waitWrite(fd.isFile); err == nil {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; continue&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; if err != nil {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return nn, err&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; if n == 0 {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return nn, io.ErrUnexpectedEOF&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }}这似乎已经处理了重传。因此,Write() 实际上确实保证了所有内容都已发送,或者发生了无法恢复的致命错误。在我看来,除了记录目的之外,根本不需要关心 n 的值。如果曾经发生错误,那么它已经足够严重以至于没有理由尝试重新传输剩余的 len(p)-n 个字节。

慕田峪7331174

这net.Conn.Write()是为了实现io.Writer接口,该接口具有以下关于错误的约定:如果返回 n < len(p),则写入必须返回非零错误。没有一个正确的写循环。对于某些情况,了解写入了多少数据可能很重要。但是,对于网络连接,基于此合同,以下内容应该有效:var err errorfor data, done := getNextSegment(); !done&&err==nil; data, done = getNextSegment() {&nbsp; _,err=conn.Write(data)}要保持写入的字节总数:var err errorwritten:=0for data, done := getNextSegment(); !done&&err==nil; data, done = getNextSegment() {&nbsp; n,err=conn.Write(data)&nbsp; written+=n}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go