我已粘贴下面的服务器端代码段。此服务器代码在正常情况下工作,但是,以下方案设法破坏代码。 服务器和客户端在同一台机器上。我使用了环回地址和实际的IP地址,没有区别。
方案
WritableByteChannel.write(ByteBuffer src)
返回12字节,这是正确的大小,但研究显示只有12个字节被写入TCP缓冲区。)key.isReadable()
条件的if子句,但然后读取失败,这表示流结束。创建SSCCE会过于复杂,如果缺少重要信息或者过于抽象,请发表评论,我会提供更多信息。
问题
如何在读取操作中新创建/接受的通道失败? 我错过了什么?我可以采取哪些措施来防止这种情况发生?
我已经尝试过wireshark,但是我无法捕获指定TCP端口上的任何数据包,即使通信正在正常工作。
问题/其他信息
代码段
Snippet 1
while (online)
{
if (selector.select(5000) == 0)
continue;
Iterator<SelectionKey> it = selector.selectedKeys().iterator();
while (it.hasNext())
{
SelectionKey key = it.next();
it.remove();
if (key.isAcceptable())
{
log.log(Level.INFO, "Starting ACCEPT!");
ServerSocketChannel serverSocketChannel = (ServerSocketChannel) key.channel();
SocketChannel channel = serverSocketChannel.accept();
channel.configureBlocking(false);
channel.register(selector, SelectionKey.OP_READ);
log.log(Level.INFO, "{0} connected to port {1}!",
new Object[] {channel.socket().getInetAddress().getHostAddress(), isa.getPort()});
}
boolean accepted = false;
if (key.isReadable())
{
log.log(Level.INFO, "Starting READ!");
SocketChannel channel = (SocketChannel) key.channel();
bb.clear();
bb.limit(Header.LENGTH);
try
{
NioUtil.read(channel, bb); // server fails here!
}
catch (IOException e)
{
channel.close();
throw e;
}
bb.flip();
Snippet 2
public static ByteBuffer read(ReadableByteChannel channel, ByteBuffer bb) throws IOException
{
while (bb.remaining() > 0)
{
int read = 0;
try
{
read = channel.read(bb);
}
catch (IOException e)
{
log.log(Level.WARNING, "Error during blocking read!", e);
throw e;
}
// this causes the problem... or indicates it
if (read == -1)
{
log.log(Level.WARNING, "Error during blocking read! Reached end of stream!");
throw new ClosedChannelException();
}
}
return bb;
}
摘录3
@Override
public boolean isServerOnline()
{
String host = address.getProperty(PropertyKeys.SOCKET_SERVER_HOST);
int port = Integer.parseInt(address.getProperty(PropertyKeys.SOCKET_SERVER_PORT));
boolean _online = true;
try
{
InetSocketAddress addr = new InetSocketAddress(InetAddress.getByName(host), port);
SocketChannel _channel = SocketChannel.open();
_channel.connect(addr);
_channel.close();
}
catch (Exception e)
{
_online = false;
}
return _online;
}
解决方案
问题不是检查的方法,如果服务可用/服务器在线。问题是EJP提到的第二点。
预计服务器会发生特定输入,如果不满足条件,则会保持不一致状态。 我已经添加了一些后备措施,现在重新连接过程 - 包括检查方法 - 工作正常。
答案 0 :(得分:3)
显然,客户端必须已关闭连接。这是read()
返回-1的唯一方式。
注意:
当ClosedChannelException
返回-1时,您正在抛出不合适的read()
。当你已经关闭频道并继续使用它时,NIO会抛出该异常。它与流的结束无关,不应该用于此。如果你必须扔东西,扔掉EOFException
。
你也不应该循环你的方式。您应该只在read()
返回正数时循环。目前,在尝试读取可能永远不会到达的数据时,您正在使选择循环挨饿。