package codec import ( "encoding/binary" "errors" "io" "github.com/panjf2000/gnet/v2" ) var ErrIncompletePacket = errors.New("incomplete packet") // TomeeSocketCodec 协议格式: // // * 0 4 // * +-----------+ // * | body len | // * +-----------+ // * | | // * + + // * | body bytes| // * + + // * | ... ... | // * +-----------+ type TomeeSocketCodec struct{} var _ SocketCodec = (*TomeeSocketCodec)(nil) func NewTomeeSocketCodec() *TomeeSocketCodec { return &TomeeSocketCodec{} } func (codec TomeeSocketCodec) Encode(buf []byte) ([]byte, error) { bodyLen := len(buf) data := make([]byte, 4+bodyLen) // 写入4字节的包长度 binary.BigEndian.PutUint32(data[:4], uint32(bodyLen)) // 写入包体 copy(data[4:], buf) return data, nil } func (codec TomeeSocketCodec) Decode(c gnet.Conn) ([]byte, error) { const maxBodyLen = 10 * 1024 * 1024 // 业务最大包体长度,按需调整 // 1. 读取4字节长度头 lenBuf, err := c.Peek(4) if err != nil { if errors.Is(err, io.ErrShortBuffer) { return nil, ErrIncompletePacket } return nil, err } // 2. 解析长度并校验上限 bodyLen := binary.BigEndian.Uint32(lenBuf) if bodyLen > maxBodyLen { return nil, errors.New("packet body exceeds max length") } totalLen := 4 + int(bodyLen) // 总包长=长度头(4)+包体 // 3. 检查整个包是否完整(关键修复:用totalLen判断) fullBuf, err := c.Peek(totalLen) if err != nil { if errors.Is(err, io.ErrShortBuffer) { return nil, ErrIncompletePacket } return nil, err } // 4. 提取包体(关键修复:跳过前4字节长度头) body := make([]byte, bodyLen) copy(body, fullBuf[4:]) // 从fullBuf[4:]开始拷贝,仅取包体 // 5. 丢弃已解析的完整数据 _, err = c.Discard(totalLen) // 原代码用_忽略err,建议处理(可选) if err != nil { return nil, err } return body, nil }