showliuzp 2025-10-14 10:55 采纳率: 84.3%
浏览 2
已结题

golang tcp拆包到结构体成员

//客户端:
package main

import (
    "bytes"
    "encoding/binary"
    "fmt"
    "net"
)

type rpc_detail struct{
    Version [2]byte //版本号
    FunsLen uint32  //函数名长度
    FunsName []byte
}


func main() {
    obj := new(rpc_detail)
    conn ,err := net.Dial("tcp",":33122")
    data := "get_data_detail-%d"

    for i:=0;i < 1;i++{
        send_data := fmt.Sprintf(data,i)

        (*obj).Version[0]   = 'v'
        (*obj).Version[1]   = '1'
        (*obj).FunsLen      = uint32(len(send_data))
        (*obj).FunsName     = []byte(send_data)

        fmt.Printf("结构体:%+v\n",*obj)
        buf := new(bytes.Buffer)
        binary.Write(buf,binary.BigEndian,obj.Version)
        binary.Write(buf,binary.BigEndian,obj.FunsLen)
        binary.Write(buf,binary.BigEndian,obj.FunsName)

        conn.Write(buf.Bytes())
        fmt.Printf("输出:%+v,err:%+v\n",buf.Bytes(),err)
    }
}


//服务端接收socket
package main

import (
        "fmt"
        "net"
        "bytes"
        "encoding/binary"
        "os"
        "io"
)

func main() {
        listener, err := net.Listen("tcp", ":33122")
        if err != nil {
                fmt.Println("Error listening:", err.Error())
                os.Exit(1)
        }
        defer listener.Close()

        fmt.Println("Server started, listening on port 33122")

        for {
                conn, err := listener.Accept()
                if err != nil {
                        fmt.Println("Error accepting: ", err.Error())
                        continue
                }

                go handleConnection(conn)
        }
}

type rpc_detail struct{
    Version     [2]byte //版本号
    FunsLen     uint32  //函数名长度
    FunsName    []byte
}

func unpack(b []byte)(obj *rpc_detail){
    buf := bytes.NewReader(b)
    
    obj = new(rpc_detail)
    err := binary.Read(buf,binary.BigEndian,&obj.Version)
    fmt.Printf("错误:%+v,版本:%+c%+c\n",err,(*obj).Version[0],(*obj).Version[1])

    err = binary.Read(buf,binary.BigEndian,&(*obj).FunsLen)
    fmt.Printf("错误:%+v,函数名长度:%+v\n",err,(*obj).FunsLen)
    
    return
}


func handleConnection(conn net.Conn) {
        defer conn.Close()

    data := make([]byte,6)
    //dataBuffer := bytes.NewReader(binaryData)
        for {
                _, err := io.ReadFull(conn, data)
                if err != nil {
                        if err == io.EOF {
                                fmt.Println("Client disconnected")
                                return
                        } else {
                                fmt.Println("Error reading from client:", err.Error())
                                return
                        }
                }

        obj := unpack(data)
        body_len := obj.FunsLen
        body_buf := make([]byte,body_len)
                _, err = io.ReadFull(conn, body_buf)
        buf := bytes.NewReader(body_buf)
        err = binary.Read(buf,binary.BigEndian,&(*obj).FunsName)
        fmt.Printf("body_buf:%+v,主体:%+v,err:%+v\n",body_buf,(*obj).FunsName,err)
        }
}


我在通过binary.Read以大端的形式读取buf到rpc_detail.FunsName,但(*obj).FunsName的打印为空,body_buf打印结果为:[103 101 116 95 100 97 116 97 95 100 101 116 97 105 108 45 48],为什么binary.Reads对(*obj).FunsName转换不成功,而Version、FunsLen都可以解析出来
  • 写回答

3条回答 默认 最新

  • 阿里嘎多学长 2025-10-14 10:56
    关注

    阿里嘎多学长整理AIGC生成,因移动端显示问题导致当前答案未能完全显示,请使用PC端查看更加详细的解答过程

    解决方案

    你想要在 Go 语言中使用 TCP 协议进行通信,并将接收到的数据拆包到结构体成员中。这里是一个示例代码:

    package main
    
    import (
        "bytes"
        "encoding/binary"
        "fmt"
        "net"
    )
    
    // rpc_data 结构体
    type rpc_data struct {
        Field1 uint32
        Field2 uint32
        Field3 uint32
    }
    
    func main() {
        // 创建 TCP 连接
        conn, err := net.Dial("tcp", "localhost:8080")
        if err != nil {
            fmt.Println(err)
            return
        }
        defer conn.Close()
    
        // 发送数据
        data := rpc_data{
            Field1: 1,
            Field2: 2,
            Field3: 3,
        }
        buf := new(bytes.Buffer)
        err = binary.Write(buf, binary.LittleEndian, data)
        if err != nil {
            fmt.Println(err)
            return
        }
        _, err = conn.Write(buf.Bytes())
        if err != nil {
            fmt.Println(err)
            return
        }
    
        // 接收数据
        var receivedData rpc_data
        err = binary.Read(conn, binary.LittleEndian, &receivedData)
        if err != nil {
            fmt.Println(err)
            return
        }
        fmt.Println(receivedData)
    }
    

    在这个示例中,我们定义了一个 rpc_data 结构体,并使用 binary.Writebinary.Read 函数来将结构体成员写入和读出 TCP 流中。注意我们使用了 LittleEndian 字节序来匹配 TCP 流中的数据。

    注意

    • 这个示例假设 TCP 服务端已经实现了数据的发送和接收逻辑。
    • 在实际应用中,需要考虑数据的校验和错误处理逻辑。
    评论

报告相同问题?

问题事件

  • 已结题 (查看结题原因) 10月14日
  • 创建了问题 10月14日