JavaNIO:何时在操作单元写入和操作单元读取之间正确切换

JavaNIO:何时在操作单元写入和操作单元读取之间正确切换,java,sockets,nio,Java,Sockets,Nio,作为一些背景: 我通过SocketChannel、SelectionKey等连接到服务器。在客户端,如果我想向服务器发送数据,我只需将数据写入ByteBuffer并通过套接字通道发送。如果所有这些都写了,我就完成了,可以返回OP_READ。如果不是全部写入,我会将剩余的字节存储在“to send”缓冲区的某个位置,并在键上标记OP_WRITE(将OP_READ替换为其唯一写入是否是个好主意?) 因此,下次调用selectNow()时,我假设它将识别OP_WRITE并尝试刷新更多数据(我将尝试使用

作为一些背景:

我通过SocketChannel、SelectionKey等连接到服务器。在客户端,如果我想向服务器发送数据,我只需将数据写入ByteBuffer并通过套接字通道发送。如果所有这些都写了,我就完成了,可以返回OP_READ。如果不是全部写入,我会将剩余的字节存储在“to send”缓冲区的某个位置,并在键上标记OP_WRITE(将OP_READ替换为其唯一写入是否是个好主意?)

因此,下次调用selectNow()时,我假设它将识别OP_WRITE并尝试刷新更多数据(我将尝试使用要写入的数据进入另一个写入循环,并在需要时重复前面的操作)

这就引出了两个问题:

  • 我应该把它留在OP_WRITE中,直到所有数据都被刷新为止吗?或者我应该改为OP_READ并尝试其间的任何读取
如果写作频道已满,而我无法写作,我是否会继续循环直到我可以开始写东西?如果连接突然阻塞,我不确定我是否应该只写我能写的,翻转回OP_READ,尝试读取,然后翻转回OP_write。据我所知,这似乎不是正确的做事方式(可能会导致大量开销不断地来回切换?)

  • 当缓冲区都已满时,处理读写批量数据的最佳方法是什么
阅读听起来很容易,因为你只是在循环,直到数据被消耗掉,但是写作。。。服务器可能只是在写,而不是在读。这将给您留下一个相当完整的发送缓冲区,而在OP_WRITE上永远循环而不读取将是不好的。你如何避免这种情况?您是否设置了一个计时器,在发送缓冲区未清除时,您可以停止尝试写入并重新开始读取?如果是这样,您是否删除OP_WRITE并记住它以备将来使用

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

目前,我只是将我的密钥设置为OP_READ,然后将其保持在该模式,等待数据,然后在且仅在写入未能发送所有数据时(WRITE()值为0)转到OP_WRITE

我应该把它留在OP_WRITE中,直到所有数据都被刷新为止吗?或者我应该改为OP_READ并尝试其间的任何读取

对此有不同的看法。我的观点是,同伴应该在发送新请求之前阅读你发送的响应的每一部分,如果他没有阅读,那他就是行为不端,你不应该提前阅读来鼓励他。否则,您最终会耗尽内存,您不应该让客户机对您这样做。当然,这假设您是请求-响应协议中的服务器。其他情况有自己的要求

如果写作频道已满,而我无法写作,我是否会继续循环直到我可以开始写东西

不,你要等OP_写信开火

如果连接突然阻塞,我不确定我是否应该只写我能写的,翻转回OP_READ,尝试读取,然后翻转回OP_write。据我所知,这似乎不是正确的做事方式(可能会导致大量开销不断地来回切换?)

开销并不重要,但在我上面描述的情况下,这样做是错误的

当缓冲区都已满时,处理读写批量数据的最佳方法是什么

一般来说,当OP_读取火灾时读取;需要的时候就写;并使用OP_WRITE告诉您何时出站失速已自行解除

你甚至需要OP_READ从网络上阅读吗


是的,否则您只需抽CPU。

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


这就是你要做的

我想我想看一些(简化的)代码。你提到了OP_WRITE和
selectNow()
,但没有提到
Selector
,只是提到了
SocketCannel
,所以我真的有点搞不懂你到底在做什么。@markspace怎么搞不懂?如果没有选择器,您将如何调用
selectNow()
?我的一些东西甚至不需要代码就可以回答,因为后半部分完全是概念性的。即使有代码,使用选择器也足够复杂。只有一个英文描述,我无法猜测到底发生了什么。如果其他人想猜,就把自己弄晕,但我不知道你到底想做什么/有问题。@markspace这很清楚。你不需要设置OP_WRITE“当你需要写的时候”。当您需要知道何时可以写入时,在写入返回零之后,以及在其他任何时间,都需要设置它。