是否可以在不高CPU使用率的情况下将NIO保持在OP_WRITE模式

And*_*rew 0 java android nio tcp

我有一个 Android 应用程序,它充当服务器,并通过 TCP 以任意间隔(5-60 秒内)从传感器提供一些数据。客户端应用程序偶尔会通过同一连接发送小块数据。数据的发送和接收必须没有任何延迟。

所有示例和教程(例如http://adblogcat.com/asynchronous-java-nio-for-dummies/)都显示或多或少相同的场景 - 阅读完成后,切换到 OP_WRITE。写入完成后切换到 OP_READ 等等。显然它不适用于我的情况。我尝试像这样同时启用读取和写入

serverChannel.register(selector, SelectionKey.OP_READ|SelectionKey.OP_WRITE);
Run Code Online (Sandbox Code Playgroud)

但它使选择器不断循环,这给 CPU 带来了很大的负载。

我确信这个问题并不完全正确,所以即使有人给我完全不同但有效的想法或我错的地方,我也会很高兴。我没有发布代码,因为它与上述教程的代码几乎相同。

use*_*421 5

你的问题和你引用的样本都是基于谬论。NIO 中不存在“模式”这样的东西。你可以随时阅读和写作,但如果在错误的时间进行,它们都将无济于事。

  • OP_READ 触发意味着读取将返回数据或流末尾,即套接字接收缓冲区中有数据或 FIN。这通常是错误的,除非对等方已发送一些数据或关闭了他的连接端。
  • OP_WRITE 触发意味着写入将传输一些数据,即套接字发送缓冲区中有空间。这通常是正确的,这就是为什么选择它通常会占用 CPU 的原因。
  • 通常,通道只能注册为 OP_READ。
  • 当你有东西要写时,就写下来。
  • 当且仅当 write()返回零时,注册 OP_WRITE 通道,记住您正在写入的缓冲区,然后返回到选择循环。
  • 当该通道触发 OP_WRITE 时,重复写入,如果完成,取消注册OP_WRITE 通道。

互联网上有很多垃圾,对于蔚来来说尤其如此。您的引文中存在众多问题(在此类材料中反复出现):

  • select()不是异步的;
  • “一次只能发生其中之一”是错误的
  • 你不需要Selector“许可”即可写入;
  • 当您有东西要写并且还不知道套接字发送缓冲区已满时,注册 OP_WRITE 并等待它触发,这只是一种精心设计且毫无意义的时间浪费;
  • 您无法更改已注册为 OP_ACCEPT 的读/写通道;
  • 关闭通道会取消密钥;
  • 关闭通道或套接字将同时关闭两者;
  • finishConnect()可以返回 false;
  • write()可以返回零或小于所提供的数据量;
  • OP_CONNECT 仅在为 true 时才能触发isConnectionPending()