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,遇到了这个问题。
提示的错误信息:
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
}
建议:
panic内容贴全,因为go的panic内容会准确输出哪个文件的哪几行panic了,以及调用链,对调试用处很大。
并不知你的服务端到底是什么,于是只能猜测。
panic: runtime error: invalid memory address or nil pointer dereference
这个错误一般出现在:一个对象本不应该为空(null,nil),但是错误地被设置成空了,然后与此同时你又去调用了它的方法。所以说某些语言都会判断
if XXX!=nil
,if (XXX!=null)
使用了错误的数组下标。
仅仅从文中看,应该是
err为nil了,但是你又去调用了err的Error方法,于是报错。
还有个建议。
虽然这样写是非常正规的封包方法,但是仍有部分可以修改的地方。
====
补充
在我这里运行为第79行报错,结果如下:
很显然,Conn已经创建成功了,并且数据也write成功了,因此
result, err := conn.Write(packet(msgInfo))
这里的err是nil。然而你又错误的认为这里有错误,强行打印err的信息,因此报错。====
至于php的pack和go的咋转换……
可能是大端小段问题,或者int长度不一致两种原因