在 Go 中使用 net.Conn.Read 读取可变长度数据
在 Go 中使用网络应用程序时,您经常会遇到以下情况:通过连接接收的数据的长度是可变的。标准库的net.Conn提供了一个名为Read的方法,它用接收到的数据填充字节数组。然而,如果您事先不知道内容的确切长度,这种方法可能会出现问题,并可能导致读取太多或不足的数据。
要解决这一挑战,一种方法是利用 bufio包裹。然而,更有效的解决方案是采用不断增长的缓冲区并读取数据,直到遇到文件结尾 (EOF):
package main import ( "fmt" "io" "net" ) func main() { // Establish a connection with a remote host. conn, err := net.Dial("tcp", "google.com:80") if err != nil { fmt.Println("dial error:", err) return } defer conn.Close() // Write a request to the connection. fmt.Fprintf(conn, "GET / HTTP/1.0\r\n\r\n") // Create a buffer to store the received data. buf := make([]byte, 0, 4096) // Read from the connection in a loop until EOF. for { // Read into a temporary buffer to avoid overwriting existing data in `buf`. tmp := make([]byte, 256) n, err := conn.Read(tmp) if err != nil { if err != io.EOF { fmt.Println("read error:", err) } break } // Append the new data to the buffer. buf = append(buf, tmp[:n]...) } fmt.Println("total size:", len(buf)) }
此解决方案分配相当大的初始缓冲区,并逐渐将其扩展为更多收到数据。它继续读取直到到达 EOF,确保缓冲区包含完整的响应。此外,它还跟踪接收到的数据的总大小。
或者,您可以将 bytes.Buffer 类型与 io.Copy 结合使用来实现类似的结果:
package main import ( "bytes" "fmt" "io" "net" ) func main() { // Establish a connection with a remote host. conn, err := net.Dial("tcp", "google.com:80") if err != nil { fmt.Println("dial error:", err) return } defer conn.Close() // Write a request to the connection. fmt.Fprintf(conn, "GET / HTTP/1.0\r\n\r\n") // Create a buffer to store the received data. var buf bytes.Buffer // Copy the data from the connection into the buffer. io.Copy(&buf, conn) fmt.Println("total size:", buf.Len()) }
这种方法使用一个可以根据需要自动扩展的缓冲区,并提供更干净、更简洁的解决方案。
以上是如何在 Go 中从网络连接读取可变长度数据?的详细内容。更多信息请关注PHP中文网其他相关文章!