scatter模式用单次read()将字节流顺序填入多个bytebuffer,适用于协议头+消息体等结构化数据;需按字段长度分配buffer并保持数组顺序,仅当读取字节数≥头部容量时方可flip处理。

Scatter模式的核心是用一个read()调用,把通道中的连续字节流按顺序填满多个ByteBuffer,适合处理结构固定的数据,比如协议头+消息体。
准备结构匹配的Buffer数组
每个Buffer容量需与数据段长度严格对应。例如协议规定前4字节是长度字段、后接不定长内容:
- 分配
header = ByteBuffer.allocate(4),不预先写入,保持初始状态 - 分配
body = ByteBuffer.allocate(8192)(按预期最大负载设) - 组合为数组:
ByteBuffer[] bufs = {header, body}
执行分散读取并检查结果
调用int bytesRead = channel.read(bufs)后,必须依据返回值判断完成状态:
- 若
bytesRead == -1,说明连接已关闭 - 若
bytesRead > 0但小于header.capacity()(如只读到2字节),则两个Buffer都未被填充,不能调用flip() - 只有当
bytesRead >= 4时,才可对header调用flip()并读出长度值,再据此调整body的limit或后续处理逻辑
注意Channel类型和Buffer一致性
该操作仅适用于FileChannel或配置为非阻塞的SocketChannel/ServerSocketChannel;DatagramChannel不支持。
- 所有Buffer必须同为heap或同为direct类型,推荐统一使用
ByteBuffer.allocateDirect()避免JVM堆内拷贝 - Buffer顺序不可颠倒:数组索引0的Buffer一定接收最前面的字节,索引1紧随其后
- 中途不可修改Buffer容量或底层数组,否则行为未定义
配合Selector处理非阻塞场景
在真实网络服务中,通常搭配Selector使用:
- 注册
OP_READ事件,收到就绪通知后再调用read(bufs) - 若一次未读完(如
body未填满但channel暂时无新数据),需保留当前Buffer position,下次就绪时继续读,无需重置 - 不要在未确认填满前就对任意Buffer调用
flip(),否则会读到无效或重复数据










