Java NIO:何时在 OP_WRITE 和 OP_READ 之间正确切换

Java NIO: When to properly switch between OP_WRITE and OP_READ

作为一些背景:

我通过 SocketChannel、SelectionKey...等连接到服务器。在客户端,如果我想向服务器发送一些东西,我只需将数据写入 ByteBuffer 并通过套接字通道发送。如果都写好了,我就完了,可以return到OP_READ。如果没有全部写完,我会把剩下的字节存储在某个地方的 "to send" 缓冲区中,然后在键上标记 OP_WRITE (替换 OP_READ 是个好主意所以它唯一的写法?)。

因此,下次我调用 selectNow() 时,我假设它会识别 OP_WRITE 并尝试刷新更多数据(我将尝试通过进入另一个写入数据的循环来完成)写,并在需要时重复前面的内容)。

这引出了两个问题:

如果写通道已满而我不能写,我是否一直循环直到我可以开始写东西?如果连接突然中断,我不确定我是否应该只写我能写的,翻回 OP_READ,尝试阅读,然后翻回 OP_WRITE。从我读过的内容来看,这似乎不是正确的做事方式(并且可能会导致不断来回切换的大量开销?)。

读取听起来很容易,因为您只需循环直到数据被消耗,但是对于写入...服务器可能只写入而不读取。这会给你留下一个相当完整的发送缓冲区,并且在 OP_WRITE 上永远循环而不读取是不好的。你如何避免这种情况?您是否设置了一个计时器,如果发送缓冲区未清除,您只是停止尝试写入并再次开始读取?如果是这样,您是否删除 OP_WRITE 并记住它以备后用?

附带问题:您甚至需要 OP_READ 从网络上阅读吗?我不确定它是否像 OP_WRITE 那样你只在特定情况下标记它(以防万一我做错了,因为我有 99.9% 的时间在 OP_READ 上)。

目前我只是将我的密钥设置为OP_READ,然后将其保留在该模式下,等待数据,然后当且仅当写入无法发送所有数据时才转到OP_WRITE( write() 值为 0).

Am I supposed to leave it in OP_WRITE until all the data has been flushed through? Or should I change to OP_READ and attempt any reads in between?

对此有不同的看法。我的意见是,同行在发送新请求之前应该阅读您发送的响应的每一部分,如果他不这样做,他只是行为不端,您不应该通过提前阅读来鼓励这一点。否则你最终只会 运行 内存不足,你不应该让客户对你这样做。当然,假设您是请求-响应协议中的服务器。其他情况各有要求。

If the writing channel is full and I can't write, do I just keep looping until I can start writing stuff through?

不,你等 OP_WRITE 开火。

If the connection suddenly gets choked, I'm unsure if I'm supposed to just write what I can, flip back to OP_READ, attempt to read, then flip back to OP_WRITE. From what I've read, this appears to not be the correct way to do things (and may cause large overhead constantly switching back and forth?).

开销并不大,但在我上述情况下这样做是错误的。

What is the optimal way to handle reading and writing bulk data when the buffers both may become full?

一般来说,在 OP_READ 触发时读取;需要的时候写;并使用 OP_WRITE 告诉您出站摊位何时解除。

Do you even need OP_READ to read from the network?

是的,否则你就抽CPU。

每当您需要编写时,只需将感兴趣的操作设置为 (OP_READ || OP_WRITE)。完成编写后,只需将感兴趣的操作设置为 OP_READ.

这就是您要做的全部。