【问题标题】:Java NIO ServerJava NIO 服务器
【发布时间】:2011-10-26 14:30:20
【问题描述】:

目前我正在开发 Java NIO 服务器(单线程)并且遇到了一些问题。服务器接受传入的连接,将初始数据包(数据包包含客户端用于进一步通信的一些数据)写入客户端,但不从中读取。服务器仅在我关闭客户端时尝试读取,当然,它返回 -1。

当接受连接时,它被注册在:

selectionKey = socketChannel.register(_selector, SelectionKey.OP_READ)

selectionKey.isReadable() 返回false(应该吗?)

在发送初始数据包之前,操作更改为:

_selectionKey.interestOps(_selectionKey.interestOps() | SelectionKey.OP_WRITE)

发送初始数据包后,操作更改为:

selectedKey.interestOps(selectedKey.interestOps() & ~SelectionKey.OP_WRITE)

数据包被发送。

可能是什么问题?会不会和客户有关?

【问题讨论】:

  • 除非绝对必要,否则你不应该构建自己的 NIO 服务器,这并不简单,还有很多注意事项,请使用像 Netty 一样为你抽象复杂性的库(@987654321 @) 或米娜 (mina.apache.org)。
  • @MaurícioLinhares 根据我对 Netty 和 MINA 的了解,它们与 NIO 一样难以驾驶。
  • 哇,这实际上是一个古老的问题,但它们与 NIO非常不同。新的 NIO API 实际上将 Netty/Mina 的一些抽象带入了 JDK,但它们与使用 Netty 之类的东西所获得的东西仍然相去甚远。
  • 我不得不说,我将 Netty 视为我的服务器的一个选项(我仍然计划在未来使用它),但我发现它还没有对 NIO 有很好的了解Netty 看起来同样复杂。不过我真的很喜欢这个项目。

标签: java nio


【解决方案1】:

selectionKey.isReadable() 返回 false(应该吗?)

当然,直到有数据要读取,或者流结束。

在发送初始数据包之前,操作更改为:

_selectionKey.interestOps(_selectionKey.interestOps() | SelectionKey.OP_WRITE)

坏主意。 OP_WRITE 几乎总是准备就绪,即除非套接字发送缓冲区已满,因此您只会导致您的 Selector.select() 方法无意识地旋转。

当您想写入频道时,只需写入即可。在经典循环中执行此操作:

while (buffer.position() > 0)
{
    buffer.flip();
    int count = channel.write(buffer);
    buffer.compact();
    if (count == 0)
    {
        // see below ...
    }
}

如果count 为零,您应该然后注册OP_WRITE,跳出循环,回到Selector 循环。如果你在没有发生这种情况的情况下退出了这个循环,注销OP_WRITE.

请注意,这意味着每个通道都有一个写入缓冲区。出于类似的原因(read() 返回零),每个通道还需要一个读取缓冲区。这反过来意味着包含它们的频道“会话”对象,这可能是频道选择键的附件。

【讨论】:

  • Selector.select() 在发送数据包并且 buffer.remaining() 返回 0 时并没有无意识地旋转。无论如何。结果是一样的:接受,写入,仅此而已。我所说的“不读”的意思不是 read() 返回零。甚至没有尝试读取通道。 Selector.select() 在切换 readyOps() 时看到 OP_WRITE 已准备就绪(当我将 interestOps() 更改为 | OP_WRITE 时),但从没有 OP_READ(即使将 interestOps() 更改为 ONLY OP_READ)。这就是问题所在。
  • (无法编辑之前的评论)Selector.select() 只有在我关闭客户端时才会看到 OP_READ。
  • 好的。刚刚尝试了不同的客户端,阅读效果很好。顺便说一句,客户端是一个MMORPG。所以,我想,这个问题与其他客户有关,或者......我以错误的方式处理它(?)。
  • @Testas (1) 除了我描述的情况外,注册 OP_WRITE 仍然没有意义。 (2) 如果 OP_READ 没有触发,则没有数据到达。就这么简单。
【解决方案2】:

OP_WRITE 仅在您想要控制滞后的极少数情况下才需要,换句话说,当接收器太慢或发送器太快时。

【讨论】:

  • “当接收方太慢或发送方太快”是同一个条件,不是两个单独的条件。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-08-07
  • 1970-01-01
  • 2018-03-30
  • 1970-01-01
  • 1970-01-01
  • 2015-04-11
  • 1970-01-01
相关资源
最近更新 更多