Tcp 谁能告诉我什么';这是golang中io.ReadFull和bytes.Buffer.ReadFrom的行为

Tcp 谁能告诉我什么';这是golang中io.ReadFull和bytes.Buffer.ReadFrom的行为,tcp,io,go,byte,buffer,Tcp,Io,Go,Byte,Buffer,我在实现tcp c/s演示时遇到了一个问题,我发现在服务器端使用io.ReadFull(conn,aByteArr)或bytes.Buffer.ReadFrom(conn)时很奇怪。在客户端退出之前,服务器似乎不会读取连接中的数据,换句话说,服务器被阻塞,但我可以使用基本的conn.read(aBuffer)读取数据。为什么这两种方法如此奇怪 因为我希望我的服务器处理任意大小的数据,所以我不喜欢使用基本方法,我是说conn.Read(),它必须先生成一个指定大小的字节片。请帮帮我 我可以给出我的

我在实现tcp c/s演示时遇到了一个问题,我发现在服务器端使用io.ReadFull(conn,aByteArr)或bytes.Buffer.ReadFrom(conn)时很奇怪。在客户端退出之前,服务器似乎不会读取连接中的数据,换句话说,服务器被阻塞,但我可以使用基本的conn.read(aBuffer)读取数据。为什么这两种方法如此奇怪

因为我希望我的服务器处理任意大小的数据,所以我不喜欢使用基本方法,我是说conn.Read(),它必须先生成一个指定大小的字节片。请帮帮我

我可以给出我的代码: 客户:


首先:您永远不会关闭客户端中建立的连接。每次调用send you时,都会呼叫一个新的conn,但绝不刷新或关闭该连接。这似乎很奇怪,可能是这里唯一的问题(例如,如果某一层缓冲你的东西,直到接近或齐平)

似乎您认为应该有一种简单的方法“从某个连接或
io.Reader
读取所有内容”。 没有。如果你对此感到不安,你不应该这样。您希望读取“任意大小的数据”,但任意大小可能意味着418 PB字节。这太多了,可能需要一些时间。我敢打赌,你没有处理这种数据大小的计算能力。读取任意大小的文件基本上需要分块读取,并分块处理,因为您无法处理418 PB的字节

分块阅读是io.Reader提供的功能。它很笨拙。这就是许多协议从数据大小开始的原因:您读取6个字节,如“1423”,解析整数,并知道您的消息长度为1432字节。从那以后,您可以使用提供的便利功能,诸如此类。即使是那些需要
EOF
s的,也可能失败


如果您的邮件没有以某些长度指示开头(或长度固定:-),您必须一直阅读到
EOF
。要使此
EOF
到达,您必须关闭发送端,否则连接仍处于打开状态,可能会决定在将来发送更多内容。

谢谢您的回答,这对我帮助很大。我遵循您的观点,在客户端完成数据发送后关闭连接,尽管还有其他错误,但服务器不再卡住
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
        }   
    }   
}
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)
    }
}