为什么 io.Copy 从套接字读取时有时会丢失行?

Why does io.Copy sometimes lose lines when reading from a socket?

请帮助我理解观察到的从套接字读取的行为。

在实验中,发送方总是发送相同的行,以'\n'结尾,然后关闭套接字的写端。

接收方的这段代码按预期工作,打印每一行:

    rdr := bufio.NewReader(sock)
    for {
        b, err := rdr.ReadBytes('\n')
        if err != nil {
            break
        }
        fmt.Print(string(b))
    }

但是,这段代码

n, err := io.Copy(os.Stdout, sock)

有时会从数据块的开头跳过随机数行,只打印其余部分(n 会相应变化,而 err 始终为 nil)。

sock 是一种自定义类型,它抽象了 net.TCPConntls.Conn,否则将在整个代码库中使用 w/o 问题。

为什么 io.Copy 读取的开头的行有时会丢失?

bufio.Reader implements buffering for an io.Reader 对象。这是什么意思?如果您使用 bufio.Readerio.Reader 源读取,它可能会从其源读取(并缓冲)比您直接从 bufio.Reader 本身读取的数据更多的数据。

这意味着如果您先使用 bufio.Readersock 读取,然后使用 io.Copy(),可能已经从 sock 读取了一些数据并坐在 bufio.Reader 的内部缓冲区中,io.Copy() 看不到也不会复制。

你不应该在同一个 io.Reader 源中混合这两个。如果必须,请务必先清空 bufio.Reader 的缓冲区,然后继续从 sock 复制,如下所示:

// First drain the buffer:
n, err := io.Copy(os.Stdout, rdr)
// Handle error

// Then proceed with the socket:
n, err = io.Copy(os.Stdout, sock)
// Handle error