有人可以告诉我golang中io.ReadFull和bytes.Buffer.ReadFrom的行为是什么

zha*_*zhi 4 io buffer byte tcp go

我在执行tcp c / s演示时遇到问题,发现在服务器端使用io.ReadFull(conn,aByteArr)或bytes.Buffer.ReadFrom(conn)时,这很奇怪,服务器似乎不会直到客户端退出,换句话说,服务器卡住,才读取连接中的数据,但是我可以使用基本的conn.Read(aBuffer)读取数据。为什么这两种方法如此奇怪?

因为我希望服务器处理任意大小的数据,所以我不喜欢使用基本方式,我的意思是conn.Read(),它必须首先创建具有指定大小的字节片。请帮我。

我可以提供我的代码:客户:

package main

import (
    "net"
    "fmt"
    "bufio"
    "time"
    "runtime"
)

func send(s string, ch chan string){
    conn, err := net.Dial("tcp", ":4000")
    if err != nil {
        fmt.Println(err)
    }   
    fmt.Fprintf(conn, s)
    fmt.Println("send: ", s)                                                                                                                                                                                      
    /*  
    s := "server run"
    conn.Write([]byte(s))
    */
    status, err := bufio.NewReader(conn).ReadString('\n')
    if err != nil {
        fmt.Println("error: ", err)
    }   
    ch <- status 
}
func main(){
    runtime.GOMAXPROCS(runtime.NumCPU())
    fmt.Println("cpu: ", runtime.NumCPU())
    ch := make(chan string, 5)
    timeout := time.After(10 * time.Second)
    i := 0

    for{
        go send(fmt.Sprintf("%s%d", "client", i), ch) 
        i++ 
        select {
            case ret := <-ch:
                fmt.Println(ret)
            case <-timeout:
                fmt.Println("time out")
                return
        }   
    }   
}
Run Code Online (Sandbox Code Playgroud)

服务器:

package main

import (
    "net"
    "log"
    "io"
    "fmt"
    "time"
    //"bytes"
)

func main(){
    // Listen on TCP port 2000 on all interfaces.
    l, err := net.Listen("tcp", ":4000")
    if err != nil {
        log.Fatal(err)
    }   
    defer l.Close()
    for {
        // Wait for a connection.
        conn, err := l.Accept()
        if err != nil {
            log.Fatal(err)
        }   
        // Handle the connection in a new goroutine.
        // The loop then returns to accepting, so that
        // multiple connections may be served concurrently.
        go func(c net.Conn) {
            fmt.Println(c.RemoteAddr())
            defer c.Close()
            // Echo all incoming data.
            /*  basic
            buf := make([]byte, 100)
            c.Read(buf)
            fmt.Println(string(buf))
            //io.Copy(c, c)
            c.Write(buf)
            // Shut down the connection.
            */

            /* use a ReadFrom
            var b bytes.Buffer                                                                                                                                                                                    
            b.ReadFrom(conn)

            fmt.Println("length: ", b.Len())
            c.Write(b.Bytes())
            */

            // use io.ReadAll
            byteArr := make([]byte, 100)

            n, err := io.ReadFull(c, byteArr)
            if err != nil {
                fmt.Println(err)
            }   
            fmt.Println(n, byteArr[:n], time.Now())
            n, _ = c.Write(byteArr[:n])
            fmt.Println("write: ", n, time.Now())
        }(conn)
    }
}   
Run Code Online (Sandbox Code Playgroud)

Vol*_*ker 5

首先:您永远不会在客户端中关闭已建立的连接。在每次调用send时,您都会建立一个新的conn,但切勿刷新或关闭该连接。这似乎很奇怪,并且可能是这里唯一的问题(例如,如果某个层将您的内容缓冲到关闭或刷新)。

看来您认为应该有一种简便的方法来“读取”某个连接或io.Reader。没有。如果您对此感到不满,则不应该如此。您想读取“任意大小的数据”,但任意大小可能意味着418 Peta字节。这很多,可能需要一些时间。我敢打赌,您没有计算能力来处理此类数据大小。读取任意大小基本上需要以块的形式读取它,并以块的形式对其进行处理,因为您无法处理418个Peta字节。

io.Reader提供块读取功能。笨拙的 这就是许多协议始于数据大小的原因:您读取了6个字节(如“ 1423”),解析了整数并知道消息长度为1432个字节。从那里,你可以使用提供了方便的功能bufio.Scannerbytes.Bufferio.ReadFull和等。甚至那些要求EOFs并可能失败。

如果您的消息不是以某些长度指示(或固定长度:-)开头,则必须阅读直到EOF。为此EOF,您必须关闭发送方,否则连接仍处于打开状态,并可能决定将来某个时候发送更多的东西。