system.arraycopy 安全分离动态头部与载荷的关键在于复制前完成协议语义校验、长度兜底和内存边界控制;需先确认非标准报文结构,明确头部结束与载荷起始偏移,再严格执行空数组、头部长度、载荷存在三重校验。

用 System.arraycopy 安全分离非标准报文块的动态头部与载荷,核心不是“复制动作本身”,而是**在复制前完成协议语义校验、长度兜底和内存边界控制**。它不解析、不判断、不校验——你得替它做完这些事,它才不会出错。
先确认报文结构与动态性来源
非标准报文的“动态头部”通常指:头部长度不固定(比如含变长字段名、TLV嵌套、或首字段为头部总长),或头部内容决定后续载荷位置(如某字节表示“从第N字节起为有效数据”)。必须明确两个关键偏移量:
-
实际头部结束位置:可能是读取前4字节得到一个整数
header_len,也可能是扫描到首个0x00或特定分隔符的位置 -
载荷起始位置:即
header_len,必须确保该值 ≤ 整个报文字节数组长度,且 ≥ 0
复制前必须做的三重校验
跳过校验直接调用 arraycopy 是多数崩溃的根源。务必按顺序执行:
- 检查原始数组非空且长度足够:
if (packet == null || packet.length == 0) return; - 提取并验证头部长度字段:
int header_len = extractHeaderLength(packet); if (header_len packet.length) throw new MalformedPacketException("invalid header length"); - 确认载荷部分存在:
if (header_len == packet.length) payloadBytes = new byte[0]; else if (header_len
用 arraycopy 分离两段,不依赖新容器
分离目标不是为了“创建新对象”,而是获得两个独立可操作的字节数组。推荐写法:
-
提取头部:
byte[] header = new byte[header_len]; System.arraycopy(packet, 0, header, 0, header_len); -
提取载荷:
int payload_len = packet.length - header_len; byte[] payload = new byte[payload_len]; System.arraycopy(packet, header_len, payload, 0, payload_len); - 避免反模式:
System.arraycopy(packet, header_len, payload, 0, Integer.MAX_VALUE)—— 不会自动截断,越界直接抛ArrayIndexOutOfBoundsException
替代方案:零拷贝视图更高效(Java 9+)
若只是读取、不修改、且后续解析逻辑支持 ByteBuffer,优先用视图代替复制:
- 构造只读缓冲区:
ByteBuffer buf = ByteBuffer.wrap(packet).asReadOnlyBuffer(); - 切片头部:
ByteBuffer headerView = buf.duplicate().limit(header_len); - 切片载荷:
ByteBuffer payloadView = buf.duplicate().position(header_len); - 优势:无内存分配、无数据拷贝;劣势:不能脱离原数组生命周期,需确保
packet不被回收











