假设我们要在可写的
SocketChannel
内向 SelectionKey
写入一些字节。
if (selectedKey.isWritable()) {
final var channel = (SocketChannel) selectedKey.channel();
assert !channel.isBlocking(); // checked!
final var buffer = (ByteBuffer) selectedKey.attachment();
assert buffer.hasRemaining(); // checked!
final var w = channel.write(buffer);
assert w >= 0; // ok, no harm
assert w > 0; // really?
}
我的问题是,
SelectionKey
可写buffer
有 剩余,我可以从技术上保证
channel.write(buffer)
的结果总是积极的吗?
从同样的角度来看,底层套接字的输出缓冲区总是有空闲空间,当
selectedKey.isWritable()
结果true
时?
附注我已经检查过文档了。
某些类型的通道,根据其状态,可能只写入部分字节,或者可能根本不写入。例如,非阻塞模式下的套接字通道写入的字节数不能多于套接字输出缓冲区中的可用字节数。
我可以从技术上保证
的结果总是积极的吗?channel.write(buffer)
TL;DR:正如问题所提出的那样,不,没有这样的保证。
非阻塞通道 I/O 的一般操作模型是,当请求 I/O 操作时,会在不阻塞的情况下传输尽可能多的字节,最多可达请求的数量。那可能是 0 字节。在您描述的条件下,这通常是正字节数,但是
如果可能有多个线程尝试写入通道,那么在选择通道可写和您关注的线程尝试写入之间,另一个线程可以向其传输足够的字节,以便通道在没有阻塞的情况下不再可写。在这种情况下,
write()
可能会返回 0。
在多种情况下,
write()
可能会引发异常而不是返回任何内容。
即使上述两种情况都不适用,Java 也根本不保证您会看到在这种情况下写入的字节数为正数,只是尝试不会阻塞。如果上述两点都不适用,则写入很可能会返回积极的结果,并且可能有一些平台可以安全地依赖它,但 Java 并不能“保证”这一点。应该为 write()
返回 0 的可能性准备好稳健的代码。
总是有空闲空间,当
selectedKey.isWritable()
结果true
时?通道的选择键表明该通道可写,意味着至少可以向该通道传输一个字节而不会阻塞。只有间接证明存在底层输出缓冲区,尽管在实践中,这确实是我所知道的所有套接字实现的工作方式。假设确实有一个输出缓冲区,是的,通道可写意味着套接字的输出缓冲区中至少有一个字节的可用空间。