TCP 套接字:消息接收来自先前连接的消息的一部分

当来自上一个连接的消息的部分转到下一个消息时,我不小心发现了一个错误。


我有一个带客户端的基本服务器。我已经删除了所有错误处理以避免示例过多膨胀。


我也用 替换了一些Printf,time.Sleep因为我没有机会及时断开连接来重现错误,因为它读取数据的速度太快了。


“包”是一个简单的结构,前 4 个字节是长度,然后是内容。


客户端代码:


package main


import (

    "encoding/binary"

    "fmt"

    "net"

)


func main() {

    conn, _ := net.Dial("tcp", "0.0.0.0:8081")

    defer conn.Close()


    str := "msadsakdjsajdklsajdklsajdk"


    // Creating a package

    buf := make([]byte, len(str)+4)

    copy(buf[4:], str)

    binary.LittleEndian.PutUint32(buf[:4], uint32(len(str)))


    for {

        _, err := conn.Write(buf)

        if err != nil {

            fmt.Println(err)

            return

        }

    }

}

因此,出于某种原因,int32Buf接收前一条消息 (d, k) 的最后 2 个字节和长度的前 2 个字节,从而产生[107, 100, 26, 0]字节切片,而它应该是[26, 0, 0, 0]. 当然,其余数据包含剩余的两个零:

http://img4.mukewang.com/63fdffca0001251f06660315.jpg


慕尼黑8549860
浏览 43回答 1
1回答

浮云间

     conn.Read(int32Buf)您需要检查 conn.Read 的返回值并将其与您的预期进行比较。您在代码中假设 conn.Read 将始终完全填充给定的 4 字节缓冲区。这个假设是错误的,即它实际上可能读取更少的数据。具体来说,它可能只读取 2 个字节,在这种情况下,您最终会\x1a\x00\x00\x00在缓冲区中得到仍然转换为 26 的消息长度。只是,消息的前 2 个字节实际上是长度的最后 2 个字节不包括在最后一次阅读中。这意味着在读取 26 个字节后,它不会读取完整的消息。2 个字节是 leg 并将包含在下一条消息中 - 这就是您观察到的。要确保读取缓冲区的确切大小,请检查 conn.Read 的返回值或使用io.ReadFull。完成此操作后,它会按预期工作(来自评论):好的,现在它完美无缺那么为什么这只发生在新连接的上下文中呢?可能是因为另一个连接导致的额外负载稍微改变了行为,但足够显着。不过,这些不是从不同连接读取的数据,而是与问题中的描述相反的当前连接读取的数据。这可以通过对不同的客户端使用不同的消息来轻松检查。
打开App,查看更多内容
随时随地看视频慕课网APP