go socket 通信 打包问题

go新手问个问题:为什么这么打包发数据,服务端错误呢,是我哪里写错了还是怎么回事?首先服务端接收的代码是C++写的。之前用PHP写的客户端发送消息是这样子的:

$body = json_encode($body);

$head = pack('IsIsIII', strlen($body), $toType, $toIp, $fromType, $fromIp, $askId, $askId2);

$dataPack = $head . $body;

socket_write($socket, $dataPack, strlen($dataPack));

然后想用go来写个demo,遇到了这个问题。
提示的错误信息:

  • vscode如何设置go二进制文件输出路径?
  • golang 如何限制内存
  • go 新建package其它包无法直接调用
  • 银联接口证书验证
  • 有熟悉golang的吗?这句话什么意思?
  • go server 不稳定
  • panic: runtime error: invalid memory address or nil pointer dereference
    [signal 0xb code=0x1 addr=0x20 pc=0x331c]
    
    goroutine 1 [running]:
    panic(0x15c7c0, 0xc82000a0d0)
        /usr/local/go/src/runtime/panic.go:481 +0x3e6
    main.main()
        /Users/fbbin/go/src/demo/socket_client.go:77 +0x55c
    exit status 2

    下面是代码

    package main
    
    import (
        "fmt"
        "net"
        "os"
        "bytes"
        "encoding/binary"
    )
    
    type Protocol struct {
        length int
        toType int
        toIp int
        fromType int
        fromIp int
        askId int
        askId2 int
        body []byte
    }
    
    func (p *Protocol) pack() ([]byte, error) {
        var packetInfo *bytes.Buffer = new(bytes.Buffer)
        var err error
        err = binary.Write(packetInfo, binary.LittleEndian, p.length)
        if err != nil {
            return nil, err
        }
        err = binary.Write(packetInfo, binary.LittleEndian, p.toType)
        if err != nil {
            return nil, err
        }
        err = binary.Write(packetInfo, binary.LittleEndian, p.toIp)
        if err != nil {
            return nil, err
        }
        err = binary.Write(packetInfo, binary.LittleEndian, p.fromType)
        if err != nil {
            return nil, err
        }
        err = binary.Write(packetInfo, binary.LittleEndian, p.fromIp)
        if err != nil {
            return nil, err
        }
        err = binary.Write(packetInfo, binary.LittleEndian, p.askId)
        if err != nil {
            return nil, err
        }
        err = binary.Write(packetInfo, binary.LittleEndian, p.askId2)
        if err != nil {
            return nil, err
        }
        err = binary.Write(packetInfo, binary.LittleEndian, p.body)
        if err != nil {
            return nil, err
        }
        return packetInfo.Bytes(), nil
    }
    
    func main() {
        server := "192.168.10.110:20001"
        tcpAddr, err := net.ResolveTCPAddr("tcp4", server)
        if err != nil {
            fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error())
            os.Exit(1)
        }
        conn, err := net.DialTCP("tcp", nil, tcpAddr)
        if err != nil {
            fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error())
            os.Exit(1)
        }
        defer conn.Close()
        fmt.Println("Connect Success!")
        msgInfo := "{\"cmdid\":\"Level.Site\",\"uid\":250}"
        // 收不到该消息
        result, err := conn.Write(packet(msgInfo))
        // 能收到,但是包内容错误
        // result, err := conn.Write([]byte(msgInfo))
        fmt.Println(result, err.Error())
    }
    
    func packet(message string) []byte {
        var bodyInfo []byte = []byte(message)
        headInfo := &Protocol{
            length:len(message),
            toType:20001,
            toIp:12039112,
            fromType:20003,
            fromIp:3812912,
            askId:12122,
            askId2:12123,
            body:bodyInfo,
        }
        packInfo, err := headInfo.pack()
        if err != nil {
            return nil
        }
        return packInfo
    }
    

  • golang url解析问题
  • 如何理解“在函数之间传递变量时,总是以值的方式传递的”这句话?
  • basic bearer token jwt oauth 有什么区别?
  • golang 指针问题
  • go语法中怎么输出变量的名字啊
  • msg[3] = byte(check & 255)这个255啥意思
  • One Solution collect form web for “go socket 通信 打包问题”

    建议:

    panic内容贴全,因为go的panic内容会准确输出哪个文件的哪几行panic了,以及调用链,对调试用处很大。

    并不知你的服务端到底是什么,于是只能猜测。

    panic: runtime error: invalid memory address or nil pointer dereference这个错误一般出现在:

    1. 一个对象本不应该为空(null,nil),但是错误地被设置成空了,然后与此同时你又去调用了它的方法。所以说某些语言都会判断 if XXX!=nil,if (XXX!=null)

    2. 使用了错误的数组下标。

    仅仅从文中看,应该是

        result, err := conn.Write(packet(msgInfo))
        // 能收到,但是包内容错误
        // result, err := conn.Write([]byte(msgInfo))
        fmt.Println(result, err.Error())

    err为nil了,但是你又去调用了err的Error方法,于是报错。

    还有个建议。

    type Protocol struct {
        length int
        toType int
        toIp int
        fromType int
        fromIp int
        askId int
        askId2 int
        body []byte
    }

    虽然这样写是非常正规的封包方法,但是仍有部分可以修改的地方。

    type Protocol struct {
        length int 
        //所有的int建议修改为uint,并且指定大小,避免不同平台出现问题,例如uint8。
        //一个uint8大小为一个byte,以此类推
        toType int
        toIp int
        fromType int
        fromIp int
        askId int
        askId2 int
        body []byte
    }

    ====
    补充

    在我这里运行为第79行报错,结果如下:

        msgInfo := "{\"cmdid\":\"Level.Site\",\"uid\":250}"
        // 收不到该消息
        result, err := conn.Write(packet(msgInfo))
        // 能收到,但是包内容错误
        // result, err := conn.Write([]byte(msgInfo))
        fmt.Println(err)                  <-  err为nil
        fmt.Println(result, err.Error())  <-所以这里报错了,nil pointer

    很显然,Conn已经创建成功了,并且数据也write成功了,因此result, err := conn.Write(packet(msgInfo))这里的err是nil。然而你又错误的认为这里有错误,强行打印err的信息,因此报错。
    ====
    至于php的pack和go的咋转换……

    可能是大端小段问题,或者int长度不一致两种原因

    .