为什么conn.Read()不会向[]byte写入任何内容,但bufio.Reader.ReadString()可以工作?

huangapple go评论82阅读模式
英文:

Why does conn.Read() write nothing into a []byte, but bufio.Reader.ReadString() works?

问题

我有一个连接,创建方式如下:

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() 不起作用呢?

英文:

I have a connection, created like this:

conn, err = net.Dial(&quot;tcp&quot;, &quot;127.0.0.1:20000&quot;)

I have tried reading from this connection in two ways. I think they both must work, but the first option doesn't.

Here is the first way of doing it:

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

The output of this method is:

[]

And here is the same thing, done with 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(&#39;\n&#39;)
	
	return
}

This function returns the response given by the server on the other end of the TCP connection.

Why does bufio.Reader.Read() work, but net.Conn.Read() doesn't?

答案1

得分: 12

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 是读取的字节数;不要忘记检查 err!

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

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

英文:

The Conn.Read() method is to implement io.Reader, the general interface to read data from any source of bytes into a []byte. Quoting from the doc of Reader.Read():

> Read reads up to len(p) bytes into p.

So Read() reads up to len(p) bytes but since you pass a nil slice, it won't read anything (length of a nil slice is 0). Please read the linked doc to know how Reader.Read() works.

Reader.Read() does not allocate a buffer ([]byte) where the read data will be stored, you have to create one and pass it, e.g.:

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

Don't forget to always check the returned error which may be io.EOF if end of data is reached. The general contract of io.Reader.Read() also allows returning some non-nil error (including io.EOF) and some read data (n &gt; 0) at the same time. The number of read bytes will be in n, which means only the first n bytes of the buf is useful (in other words: buf[:n]).

Your other example using bufio.Reader works because you called Reader.ReadString() which doesn't require a []byte argument. If you would've used the bufio.Reader.Read() method, you would also had to pass a non-nil slice in order to actually get some data.

huangapple
  • 本文由 发表于 2016年1月11日 16:50:45
  • 转载请务必保留本文链接:https://go.coder-hub.com/34717331.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定