hasRemaining()仅判断缓冲区是否有剩余字节,不能确保数据完整写出;完整写入需结合write返回值检查与循环重试:返回>0继续,=0注册OP_WRITE等待就绪,<0关闭连接。

在非阻塞 IO 中,hasRemaining() 本身不是“确保数据完整写出”的充分条件,它只是判断缓冲区是否还有未处理的字节;真正保证写入完整的标准范式,是一组配合 Channel 写操作的状态检查与循环重试逻辑。
hasRemaining() 的真实作用
它只反映当前 position 与 limit 之间是否还有可读/可写字节,不涉及底层通道是否就绪、是否写完、是否阻塞或系统缓冲区是否耗尽。调用 channel.write(buffer) 后,buffer 的 position 会前移,limit 不变——但实际写入字节数可能小于 buffer 中剩余字节数(尤其在非阻塞模式下)。
非阻塞 write 的典型返回值含义
当调用 SocketChannel.write(ByteBuffer) 时:
- 返回值 > 0:表示成功写入的字节数(可能小于
buffer.remaining()) - 返回值 == 0:通道尚未就绪(如 TCP 窗口满、内核发送缓冲区暂满),需等待下次就绪再写
- 返回值 < 0:连接已关闭(对端 close 或 RST)
标准循环写入范式(带状态管理)
正确做法是:每次 write 后检查返回值,并仅在仍有剩余且通道未就绪时暂停,而非盲目依赖 hasRemaining() 一直循环。
- 先调用
buffer.flip()(写完后切到读模式) - 进入 while 循环:
while (buffer.hasRemaining()) - 执行
int written = channel.write(buffer) - 若
written == 0,说明通道暂时不可写,应注册OP_WRITE并让 Selector 回调,或直接 break 等待下一次轮询 - 若
written > 0,继续循环(position 已更新,hasRemaining()自动变小) - 若
written < 0,清理资源并关闭连接
为什么不能只靠 hasRemaining() 就认为“写完了”
例如:一个 8KB 的 buffer 调用 write,首次只成功写入 2KB(返回 2048),此时 buffer.hasRemaining() 仍为 true,但若线程立即退出或未重试,就丢失了剩余 6KB。更危险的是,在非阻塞模式下反复调用 write 而不检查返回值,可能陷入空转(busy-spin),浪费 CPU 却无进展。

















