7days-golang icon indicating copy to clipboard operation
7days-golang copied to clipboard

序列化和反序列化问题

Open shangxiaomi opened this issue 4 years ago • 4 comments

我在写demo时,向一个网络连接中先发送一个json的数据,再发送一个gob的数据。 然后使用json解码器进行解码,json解码器这时会把两个数据都从网络连接中读出来,存在json解码器解码后,造成gob解码器无法获取到对应的数据,作者的rpc框架也是用的json解码器和gob解码器,并且也是先发送json数据,再发送gob数据,在测试中没有发现这个问题,请问是如何避免的?

shangxiaomi avatar Mar 14 '21 17:03 shangxiaomi

作者是先发送option,再发送header+body的。 _ = json.NewEncoder(conn).Encode(geerpc.DefaultOption) 这句话执行完,conn就已经把json格式的option数据发到服务端了,服务端处理之后,客户端才发送header和body,然后服务端继续处理。

正常测试是刚刚说的这个流程,但是如果你用一些极限情况压测下,可能会出现你说的情况。

这块知识属于 tcp粘包 问题,另外还有 拆包 问题,你可以去了解下。

yudidi avatar Mar 24 '21 04:03 yudidi

113541748-70730d80-9615-11eb-9be1-89d49ffd0cab 我直接下载作者rpc day1的代码运行就会阻塞在readRequestHeader这里。 113541900-b4fea900-9615-11eb-85c2-16476a7458ff client发送应该是没问题的。感觉就是tcp粘包的问题,如果不发option,程序就可以进行下去。

liyuxuan89 avatar Apr 05 '21 06:04 liyuxuan89

请问有解决这个问题的吗

4ttenji avatar May 28 '21 09:05 4ttenji

可以给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)
}

Outlying3720 avatar Apr 07 '24 13:04 Outlying3720