【问题标题】:can someone tell me what's the behavior of io.ReadFull and bytes.Buffer.ReadFrom in golang有人可以告诉我 io.ReadFull 和 bytes.Buffer.ReadFrom 在 golang 中的行为是什么
【发布时间】:2014-02-03 23:55:42
【问题描述】:

我在实现 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
        }   
    }   
}

服务器:

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)
    }
}   

【问题讨论】:

    标签: tcp io go byte buffer


    【解决方案1】:

    首先:您永远不会关闭客户端中建立的连接。在每次调用 send 时,您都会拨打一个新的连接,但从不刷新或关闭该连接。这看起来很奇怪,可能是这里唯一的问题(例如,如果某些层将您的东西缓冲到关闭或刷新)。

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

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

    如果您的消息没有以某种长度指示开头(或者是固定长度:-),您将不得不阅读到EOF。要让这个EOF 到达,您必须关闭发送端,否则连接仍处于打开状态,并且可能决定在未来某个时间发送更多内容。

    【讨论】:

    • 谢谢你的回答,对我帮助很大。我按照你的观点,在客户端完成发送数据后关闭连接,虽然还有其他错误,但服务器不再卡住了
    猜你喜欢
    • 2021-11-16
    • 2014-11-25
    • 2020-12-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-20
    相关资源
    最近更新 更多