【问题标题】:Why does conn.Read() write nothing into a []byte, but bufio.Reader.ReadString() works?为什么 conn.Read() 不向 []byte 写入任何内容,但 bufio.Reader.ReadString() 有效?
【发布时间】:2016-04-15 12:19:56
【问题描述】:

我有一个连接,是这样创建的:

conn, err = net.Dial("tcp", "127.0.0.1:20000")

我尝试通过两种方式读取此连接。我认为他们都必须工作,但第一个选项没有。

这是第一种方法:

var bytes []byte
for i := 0; i < 4; i++ {
    conn.Read(bytes)
}
fmt.Printf("%v", bytes)

这个方法的输出是:

[]

这也是同样的事情,用bufio.Reader 完成:

func readResponse(conn net.Conn) (response string, err error) {
    reader := bufio.NewReader(conn)
    _, err = reader.Discard(8)
    if err != nil {
        return
    }

    response, err = reader.ReadString('\n')

    return
}

该函数返回TCP连接另一端的服务器给出的响应。

为什么bufio.Reader.Read() 有效,而net.Conn.Read() 无效?

【问题讨论】:

  • 嗯,这很明显:Read 读取提供的[]byte。您的 []byte 是空的,它的长度为零,并且整个零长度已被填充。因此,从技术上讲,您的 Readcall 可以正常工作,因为它用来自连接的数据完全填充了提供的字节片。你参加了围棋巡回赛?
  • 谢谢。我对很多概念都很陌生,所以我在游览中或第一次查看函数文档时读到的一些内容在我没有意识到的情况下超出了我的脑海。很抱歉让您感到不快。

标签: go connection bufferedreader reader


【解决方案1】:

Conn.Read() 方法是实现io.Reader 的通用接口,用于从任何字节源读取数据到[]byte 中。引用Reader.Read()的文档:

Read 最多将 len(p) 个字节读入 p。

所以Read() 最多读取len(p) 字节,但由于您传递了nil 切片,它不会读取任何内容(nil 切片的长度为0)。请阅读链接文档以了解 Reader.Read() 的工作原理。

Reader.Read() 没有分配缓冲区([]byte)来存储读取的数据,您必须创建一个并传递它,例如:

var buf = make([]byte, 100)
n, err := conn.Read(buf)
// n is the number of read bytes; don't forget to check err!

不要忘记始终检查返回的error,如果到达数据末尾,它可能是io.EOFio.Reader.Read() 的通用合约还允许同时返回一些非nil 错误(包括io.EOF)和一些读取数据(n &gt; 0。读取的字节数将在n 中,这意味着只有buf 的第一个n 字节是有用的(换句话说:buf[:n])。

您使用bufio.Reader 的另一个示例有效,因为您调用了不需要[]byte 参数的Reader.ReadString()。如果您使用bufio.Reader.Read() 方法,您还必须传递非nil 切片才能实际获取一些数据。

【讨论】:

  • 我还注意到,新手经常会被Read() 的错误期望所绊倒,因为它会读取如此多的数据来填满整个切片。 “问题”在文档字符串中的那些“最多”字中,实际上表示“1 到输入缓冲区长度之间的任意数量的字节”。要填满整个缓冲区,应该使用io.ReadFull()。此行为遵循read() syscall of POSIX 的语义。
猜你喜欢
  • 2020-04-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-12-01
  • 2012-11-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多