【问题标题】:Java NIO: When to properly switch between OP_WRITE and OP_READJava NIO:何时在 OP_WRITE 和 OP_READ 之间正确切换
【发布时间】:2015-09-08 06:21:59
【问题描述】:

作为一些背景:

我通过 SocketChannel、SelectionKey...等连接到服务器。在客户端,如果我想向服务器发送一些东西,我只需将我的数据写入一个 ByteBuffer 并通过套接字通道发送。如果所有的都写好了,我就完成了,可以返回到 OP_READ。如果不是全部写入,我将剩余的字节取出,将它们存储在某处的“发送”缓冲区中,并在键上标记 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_READ 上)。

目前我只是将我的密钥设置为 OP_READ,然后将其置于该模式,等待数据,然后当且仅当写入失败发送所有数据时才转到 OP_WRITE(write() 值为 0)。

【问题讨论】:

  • 我想我想看看一些(简化的)代码。你提到了 OP_WRITE 和selectNow(),但没有提到Selector,只是SocketChannel,所以我真的很困惑你到底在做什么。
  • @markspace 它是如何令人困惑的?选择器是隐含的,你怎么称呼selectNow() 没有一个选择器?我的一些东西甚至不需要代码就可以回答,因为后半部分纯粹是概念性的。
  • 即使使用代码,使用选择器也足够复杂。只有英文描述,我无法猜测实际发生了什么。如果其他人想猜测,请把自己打晕,但我不知道你真正想做什么/有什么问题。
  • @markspace 非常清楚。

标签: java sockets nio


【解决方案1】:

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

这就是你所要做的。

【讨论】:

  • 你不需要设置 OP_WRITE '当你需要写'。当您需要知道何时可以写入、写入返回零之后以及其他任何时间时,您都需要设置它。
【解决方案2】:

我是否应该将其保留在 OP_WRITE 中,直到所有数据都被刷新?还是应该更改为 OP_READ 并尝试在其间进行任何读取?

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

如果写作频道满了,我写不出来,我是不是一直循环,直到我可以开始写东西?

不,您等待 OP_WRITE 触发。

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

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

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

一般来说,在 OP_READ 触发时读取;随时随地写;并使用 OP_WRITE 告诉您出站摊位何时自行释放。

你甚至需要 OP_READ 来从网络读取数据吗?

是的,否则你只会抽 CPU。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-09
    • 1970-01-01
    • 1970-01-01
    • 2014-01-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多