7days-golang
7days-golang copied to clipboard
序列化和反序列化问题
我在写demo时,向一个网络连接中先发送一个json的数据,再发送一个gob的数据。 然后使用json解码器进行解码,json解码器这时会把两个数据都从网络连接中读出来,存在json解码器解码后,造成gob解码器无法获取到对应的数据,作者的rpc框架也是用的json解码器和gob解码器,并且也是先发送json数据,再发送gob数据,在测试中没有发现这个问题,请问是如何避免的?
作者是先发送option,再发送header+body的。
_ = json.NewEncoder(conn).Encode(geerpc.DefaultOption) 这句话执行完,conn就已经把json格式的option数据发到服务端了,服务端处理之后,客户端才发送header和body,然后服务端继续处理。
正常测试是刚刚说的这个流程,但是如果你用一些极限情况压测下,可能会出现你说的情况。
这块知识属于 tcp粘包 问题,另外还有 拆包 问题,你可以去了解下。
我直接下载作者rpc day1的代码运行就会阻塞在readRequestHeader这里。
client发送应该是没问题的。感觉就是tcp粘包的问题,如果不发option,程序就可以进行下去。
请问有解决这个问题的吗
可以给json包添加长度header,解决json Decoder吞掉部分gob包的问题
client代码
func NewClient(conn net.Conn, opt *Option) (*Client, error) {
f := codec.NewCodecFuncMap[opt.CodecType]
if f == nil {
err := fmt.Errorf("invalid codec type %s", opt.CodecType)
log.Println("rpc client: codec error:", err)
return nil, err
}
jsonBytes, err := json.Marshal(opt)
if err != nil {
log.Println("rpc client: options err:", err)
_ = conn.Close()
return nil, err
}
lenJsonBytes := make([]byte, 2)
binary.BigEndian.PutUint16(lenJsonBytes, uint16(len(jsonBytes)))
conn.Write(lenJsonBytes)
conn.Write(jsonBytes)
return newClientCodec(f(conn), opt), nil
}
server代码
func (server *Server) ServeConn(conn net.Conn) {
defer func() { _ = conn.Close() }()
var opt Option
// time.Sleep(time.Second)
lenJsonBytes := make([]byte, 2)
conn.Read(lenJsonBytes)
jsonLength := binary.BigEndian.Uint16(lenJsonBytes)
log.Println("rpc server: json length:", jsonLength)
jsonBytes := make([]byte, jsonLength)
_, err := conn.Read(jsonBytes)
if err != nil {
log.Println("rpc server: read json bytes error:", err)
return
}
if err := json.Unmarshal(jsonBytes, &opt); err != nil {
log.Println("rpc server: options error:", err)
return
}
if opt.MagicNumber != MagicNumber {
log.Printf("rpc server: invalid magic number: %x\n", opt.MagicNumber)
return
}
f := codec.NewCodecFuncMap[opt.CodecType]
if f == nil {
log.Println("rpc server: invalid codec type: ", opt.CodecType)
return
}
log.Println("rpc server: communicate start with codec type: ", opt.CodecType)
server.serveCodec(f(conn), &opt)
}