使用Golang net.Conn.Read读取整个数据

使用Golang net.Conn.Read读取整个数据,go,Go,因此,我在Go中构建了一个网络应用程序,我看到Conn.Read读取有限字节数组,这是我用make([]byte,2048)创建的,现在的问题是,我不知道内容的确切长度,因此可能太长,也可能不够。 我的问题是,我如何才能读取准确的数据量。我想我必须使用bufio,但我不确定。您可以读取如下数据: // import net/textproto import ("net/textproto", ...) .... reader := bufio.NewReader(Conn) tp := te

因此,我在Go中构建了一个网络应用程序,我看到
Conn.Read
读取有限字节数组,这是我用
make([]byte,2048)
创建的,现在的问题是,我不知道内容的确切长度,因此可能太长,也可能不够。

我的问题是,我如何才能读取准确的数据量。我想我必须使用
bufio
,但我不确定。

您可以读取如下数据:

// import net/textproto
import ("net/textproto", ...)

....

reader := bufio.NewReader(Conn)
tp := textproto.NewReader(reader)

defer Conn.Close()

for {
    // read one line (ended with \n or \r\n)
    line, _ := tp.ReadLine()
    // do something with data here, concat, handle and etc... 
}
....
func main() {
    conn, err := net.Dial("tcp", "google.com:80")
    if err != nil {
        fmt.Println("dial error:", err)
        return
    }
    defer conn.Close()
    fmt.Fprintf(conn, "GET / HTTP/1.0\r\n\r\n")

    buf := make([]byte, 0, 4096) // big buffer
    tmp := make([]byte, 256)     // using small tmo buffer for demonstrating
    for {
        n, err := conn.Read(tmp)
        if err != nil {
            if err != io.EOF {
                fmt.Println("read error:", err)
            }
            break
        }
        //fmt.Println("got", n, "bytes.")
        buf = append(buf, tmp[:n]...)

    }
    fmt.Println("total size:", len(buf))
    //fmt.Println(string(buf))
}

这在很大程度上取决于您正在尝试做什么,以及您期望的数据类型,例如,如果您只想在EOF之前读取数据,您可以使用以下内容:

// import net/textproto
import ("net/textproto", ...)

....

reader := bufio.NewReader(Conn)
tp := textproto.NewReader(reader)

defer Conn.Close()

for {
    // read one line (ended with \n or \r\n)
    line, _ := tp.ReadLine()
    // do something with data here, concat, handle and etc... 
}
....
func main() {
    conn, err := net.Dial("tcp", "google.com:80")
    if err != nil {
        fmt.Println("dial error:", err)
        return
    }
    defer conn.Close()
    fmt.Fprintf(conn, "GET / HTTP/1.0\r\n\r\n")

    buf := make([]byte, 0, 4096) // big buffer
    tmp := make([]byte, 256)     // using small tmo buffer for demonstrating
    for {
        n, err := conn.Read(tmp)
        if err != nil {
            if err != io.EOF {
                fmt.Println("read error:", err)
            }
            break
        }
        //fmt.Println("got", n, "bytes.")
        buf = append(buf, tmp[:n]...)

    }
    fmt.Println("total size:", len(buf))
    //fmt.Println(string(buf))
}
//编辑:为了完整性和@fabrizioM的伟大建议,我完全没有想到:

func main() {
    conn, err := net.Dial("tcp", "google.com:80")
    if err != nil {
        fmt.Println("dial error:", err)
        return
    }
    defer conn.Close()
    fmt.Fprintf(conn, "GET / HTTP/1.0\r\n\r\n")
    var buf bytes.Buffer
    io.Copy(&buf, conn)
    fmt.Println("total size:", buf.Len())
}
您可以使用以下功能:

import (
    "fmt"
    "io/ioutil"
    "net"
)

func whois(domain, server string) ([]byte, error) {
    conn, err := net.Dial("tcp", server+":43")
    if err != nil {
        return nil, err
    }
    defer conn.Close()

    fmt.Fprintf(conn, "%s\r\n", domain)
    return ioutil.ReadAll(conn)
}

难道没有更有效的方法吗?还有,有没有一种方法可以让我不必使用无限循环?告诉我们你正在尝试读取什么样的数据,否则这只是一个偶然的机会。谢谢你,我已经考虑过这个(Python socket.recv),但我有点不知所措,所以不知道如何实现它。如果你想复制所有的内容,也可以使用io.copy(conn,NewBuffer)我的理解是conn.Read(buf)是阻塞的,如果可能的话,它将读取缓冲区的整个长度,或者读取到EOF的点,在该点上,n将不同于cap(buf)-但可能与len(buf)相同,如果它是用3个参数声明的。对吗?如果读循环得到
io.EOF
和一个非零
n
,则可能无法打印最后几个字节。根据
io.Reader
的文档,这可能会发生。我更喜欢使用“tmp”缓冲区的第一种方法,您可以完全控制正在进行的操作打开。它允许您处理通过连接的任何大小的输入,而不会出现“内存不足”的风险例如,错误。这个函数对我来说似乎是挂起的,永远不会得到任何结果response@BrianLeishman你是指我作为示例编写的
whois
函数还是
ioutil.ReadAll
函数?如果是后者,很可能意味着你传递的
Reader
既没有到达EOF也没有出错。我发现两者都是但在我的具体情况下,我试图读取IMAP连接上的所有响应,但直到您自己关闭响应,使其“挂起”(后来我正确地读取了行,直到得到最终响应,然后停止读取更多行),响应才真正完成,但我将其粘贴到一个空白的新.go文件中,却从未返回任何结果