You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TCP Socket消息串扰Bug求助:旧连接消息片段混入新消息如何解决?

发现TCP Socket数据粘包问题:前一消息片段混入下一条消息

意外发现一个TCP Socket数据粘包问题:前一个连接的消息片段会混入下一条消息中。我搭建了基础的客户端-服务端Demo,为简化示例移除了所有错误处理;由于数据读取过快无法及时断开连接复现Bug,故将部分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"

    // 创建数据包
    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
        }
    }
}

服务端代码

package main

import (
    "encoding/binary"
    "fmt"
    "net"
    "sync"
    "time"
)

func ReadConnection(conn net.Conn, buf []byte) (err error) {
    maxLen := cap(buf)
    readSize := 0
    for readSize < maxLen {
        // 替换Printf为sleep
        time.Sleep(time.Nanosecond * 10)

        readN, err := conn.Read(buf[readSize:])
        if err != nil {
            return err
        }
        readSize += readN
    }
    return nil
}

func handleConnection(conn net.Conn, waitGroup *sync.WaitGroup) {
    waitGroup.Add(1)
    defer conn.Close()
    defer waitGroup.Done()

    fmt.Printf("服务连接 %s\n", conn.RemoteAddr().String())

    var packageSize int32 = 0
    int32Buf := make([]byte, 4)

    for {
        // 读取长度
        conn.Read(int32Buf)
        packageSize = int32(binary.LittleEndian.Uint32(int32Buf))

        // 假设长度应为26
        if packageSize > 26 {
            fmt.Println("数据包大小错误")
            return
        }

        // 读取内容
        packageBuf := make([]byte, packageSize)
        if err := ReadConnection(conn, packageBuf); err != nil {
            fmt.Printf("错误: %s\n", err)
            return
        }

        // 替换Printf为sleep
        time.Sleep(time.Nanosecond * 100)
    }
}

func main() {
    // 建立监听
    listener, _ := net.Listen("tcp", "0.0.0.0:8081")
    defer listener.Close()

    waitGroup := sync.WaitGroup{}
    for {
        conn, err := listener.Accept()
        if err != nil {
            break
        }

        go handleConnection(conn, &waitGroup)
    }

    waitGroup.Wait()
}

问题现象

服务端读取包长度时,int32Buf会接收到前一条消息的最后2字节(d、k)与当前包长度的前2字节,形成[107,100,26,0]的字节切片(正确应为[26,0,0,0]),导致解析出错误的包长度,触发包大小错误提示。

异常数据截图:
异常数据截图


内容的提问来源于stack exchange,提问作者LiaVa

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 04:55:24