NIO Gather模式通过channel.write()一次性发送多个已flip的ByteBuffer,按数组顺序写出position到limit间数据,无需拼接;须全用allocateDirect或全allocate,返回值指示实际字节数,未写完可复用原Buffer继续发送。

用NIO的Gather模式一次性把多个缓冲区的数据写入通道,核心是让不同逻辑部分(比如状态码、JSON体、换行符)各占一个ByteBuffer,再统一交给channel.write()处理——它会按数组顺序把每个Buffer里position到limit之间的有效字节连续发出,无需手动拼接或复制。
准备已填充并flip过的Buffer数组
每个Buffer必须独立完成写入和翻转操作,确保position在开头、limit标出真实数据边界:
- 用
put()写入内容,例如statusBuf.put("OK".getBytes()) - 调用
flip()切换为读模式,此时limit固定为写入长度,position归零 - 所有Buffer类型需一致:全用
allocateDirect()(推荐)或全用allocate(),混用会抛异常
调用write并检查返回值
传入Buffer数组后,write按序写出,但不保证一次写完:
-
long written = channel.write(bufs)返回本次实际写出的总字节数 - 若
written ,说明网络缓冲区满,未写完的Buffer仍保持当前position和limit,下次可直接复用write继续发送 - 不需要重新
flip()或clear(),避免覆盖未发送数据
典型结构示例:构造HTTP风格响应
比如发送"200"状态码 + {"data":"ok"} + "\r\n":
statusBuf = ByteBuffer.allocateDirect(3).put("200".getBytes()).flip()bodyBuf = ByteBuffer.allocateDirect(16).put("{\"data\":\"ok\"}".getBytes()).flip()crlfBuf = ByteBuffer.allocateDirect(2).put((byte)'\r').put((byte)'\n').flip()- 调用
channel.write(new ByteBuffer[]{statusBuf, bodyBuf, crlfBuf}),底层等效于拼接后发送
注意事项与常见陷阱
避开这几个关键点才能稳定运行:
- 仅支持
GatheringByteChannel子类:即FileChannel和非阻塞SocketChannel,阻塞式SocketChannel不支持 - Buffer顺序敏感:数组索引0的内容一定最先发出,不能靠后续逻辑调整顺序
- 不自动处理粘包/半包:Gather只管“怎么发”,不管“发多少次”或“对方如何收”,需配合应用层协议设计
- 避免在write中途修改Buffer内容:一旦开始写,就别对这些Buffer做
put()或clear(),否则行为未定义










