我正在研究一个基本的最小服务器概念,使用 NIO 和套接字通道将数据从一个端口传输到另一个目的地。事情在全速、快速链接等情况下运行良好。当一方比另一方快时,事情会非常失败并消耗大量 CPU。事情有效,只是工作效率低下。例子:Iterator keys = selector.selectedKeys().iterator();while (keys.hasNext()) { SelectionKey key = (SelectionKey) keys.next(); keys.remove(); try { if (!key.isValid()) continue; if (key.isReadable()) read(key); } catch (Exception e) { e.printStackTrace(); key.cancel(); }}只要套接字有可以读取的数据,就会调用读取。但是,如果由于客户端具有高延迟或只是没有快速读取数据而无法写入此套接字的可写部分怎么办?我们最终以疯狂的速度循环,直到释放更多可写缓冲区为止:public void read(SelectionKey key) throws IOException { ByteBuffer b = (ByteBuffer) buffers.get(readable); //prior buffer that may or may not have been fully used from the prior write attempt int bytes_read = readable.read(b); b.flip(); if (bytes_read > 0 || b.position() > 0) writeable.write(b); b.compact();}所以说我们可以从千兆位的套接字读取,但接收器只能从我们的可写套接字以 100 千位读取......我们可能会在可以写入客户端的每个小数据之间循环一百万次,因为它们只是没有像我们想要的那样快地消耗套接字缓冲区中的数据。如果我用一个线程来做这件事,就不会有问题,因为我们会阻塞写调用。但是对于 NIO,您应该怎么做才能让它跳过已读通知?
1 回答

白衣非少年
TA贡献1155条经验 获得超0个赞
我想通了这一点。我仍然没有找到指向我这一点的文档,但是在考虑了更多事情之后,我意识到这就是 OP_WRITEABLE 场景的用途。
因此,当可写返回它接受 0 字节时,我取消注册可读通道上的 OP_READ,并在可写通道上注册 OP_WRITEABLE。一旦我被告知它是可写的,我就会换回读/写通道,包括它们现在为删除 OP_WRITEABLE 而注册的内容。
因此,当无法完成写入时,请取消注册触发您尝试写入的读取,并在其上注册写入通知。一旦你得到了,换回注册。
现在一切正常。
添加回答
举报
0/150
提交
取消