我正在编写一个使用 NIO 套接字的 Java 应用程序。它由 3 个服务端和一组客户端组成。客户端可以与服务端通信,而服务端可以与客户端以及其他服务端通信。
服务器与服务器以及客户端与服务器之间会发送已序列化为 byte[] 数组的 Message。每个 Message 的第一个字节包含消息的大小,并且自然保证每个消息不超过 127 (2^8 -1) 字节。你可以将服务器和客户端发送消息的操作视为循环执行:
然后,实现使用了ByteBuffer。像Java NIO实现中的任何一个一样,每个服务器都会执行selector.select(),然后检索SelectionKeys,看看是否需要处理读取(调用handleRead()方法)、写入(调用handleWrite()方法)或接受(调用handleAccept()方法)。所有的handleXX方法都采取有限数量的步骤,不会阻塞等待任何其他内容。
在为特定key检索数据(handleRead())时,我只是将数据存储在特定的map(Map<SelectionKey, List<byte[]>> readDataForKey)中。然后遍历列表并提取所有已接收到的消息。
然而,我注意到有时在为某些键输入handleRead时,有数千条消息要等待处理。我无法弄清楚为什么会这样? 我期望handleRead只能看到一些消息,然后就可以结束了。
有时候会积累数千条消息未被处理。这是什么意思?这意味着我的handleRead或handleWrite或NIO实现的其他部分花费了太长时间,底层缓冲区变满了吗?这意味着偶尔会出现GC甚至(约10毫秒),在此期间缓冲区变满了吗?这意味着我的代码在handleRead中可能很慢,因此消息被积累了吗?
这么多消息积累起来是正常的吗?
服务器与服务器以及客户端与服务器之间会发送已序列化为 byte[] 数组的 Message。每个 Message 的第一个字节包含消息的大小,并且自然保证每个消息不超过 127 (2^8 -1) 字节。你可以将服务器和客户端发送消息的操作视为循环执行:
Message msg = new Message()
while (true) {
sendMessage(msg, server or client)
receiveMessage()
}
然后,实现使用了ByteBuffer。像Java NIO实现中的任何一个一样,每个服务器都会执行selector.select(),然后检索SelectionKeys,看看是否需要处理读取(调用handleRead()方法)、写入(调用handleWrite()方法)或接受(调用handleAccept()方法)。所有的handleXX方法都采取有限数量的步骤,不会阻塞等待任何其他内容。
在为特定key检索数据(handleRead())时,我只是将数据存储在特定的map(Map<SelectionKey, List<byte[]>> readDataForKey)中。然后遍历列表并提取所有已接收到的消息。
然而,我注意到有时在为某些键输入handleRead时,有数千条消息要等待处理。我无法弄清楚为什么会这样? 我期望handleRead只能看到一些消息,然后就可以结束了。
有时候会积累数千条消息未被处理。这是什么意思?这意味着我的handleRead或handleWrite或NIO实现的其他部分花费了太长时间,底层缓冲区变满了吗?这意味着偶尔会出现GC甚至(约10毫秒),在此期间缓冲区变满了吗?这意味着我的代码在handleRead中可能很慢,因此消息被积累了吗?
这么多消息积累起来是正常的吗?
ByteBuffer
大小而导致了累积?例如,如果缓冲区太大,这会使Java在调用处理程序之前填充更多的消息吗? - insumity