【发布时间】:2015-10-11 13:23:46
【问题描述】:
我正在尝试基于非阻塞 NIO 消息开发自己的通信库。我已经阅读了 1000 篇关于它的教程和书籍章节,我认为最后我有一些可以同时连接很少的东西。但是,当我在服务器端同时存在许多连接时,我遇到了一些问题。
我有 4 个私有方法的典型选择器实现:accept、finishConnect、read 和 write。我的问题在于前两个问题:Accept 和 finishConnect。
当客户端打开一个新的套接字,并且一个可接受的键唤醒选择器时,执行以下代码。
private void accept(SelectionKey key) {
try {
ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
SocketChannel sc = ssc.accept();
sc.configureBlocking(false);
LOGGER.debug("Socket " + sc.hashCode() + "-" + sc.socket().toString() + " connexion completed");
changeInterest(sc, SelectionKey.OP_READ);
eventManager.addEvent(new ConnectionEstablished(sc));
} catch (Throwable e) {
NIOException ne = new NIOException(NIOException.ErrorType.ACCEPTING_CONNECTION, e);
eventManager.addEvent(new ErrorEvent(null, ne));
}
}
在客户端,我有一个 connect 方法的实现,一旦服务器处理其可接受的套接字密钥,就会调用该方法。
private void finishConnect(SelectionKey key) {
SocketChannel sc = (SocketChannel) key.channel();
try {
if (sc.finishConnect()) {
eventManager.addEvent(new ConnectionEstablished(sc));
LOGGER.debug("Socket " + sc.hashCode() + "-" + sc.socket().toString() + " connection finished");
} else {
LOGGER.debug("REFUSED " + sc + " - " + sc.socket().toString());
refusedConnection(sc, null);
key.cancel();
}
} catch (Exception e) {
refusedConnection(sc, e);
key.cancel();
}
}
问题是,当我创建一些连接被接受时,客户端会执行 finishConnect 消息(我可以看到使用所用端口建立的套接字连接)。但是我在服务器端找不到这个连接接受,没有使用这些端口的连接完成日志消息!!
我怀疑 ssc.accept() 和日志调用之间可能会出现异常,因此我添加了一些额外的日志消息来检查是哪条指令破坏了所有内容。进入接受方法的所有键的序列都已完成。
如果我什至在日志上看不到任何错误消息,这怎么可能?
编辑:我对一次打开的套接字数量进行了一些测试。当客户端开始运行时,服务器上只有一个 openSocket:服务器套接字。之后,它有多达 200 个同时打开的套接字,并且在客户端执行结束时,服务器返回到 1 个打开的套接字。我猜他们从来没有被计算在内
到目前为止,我已经制定了一种解决方法,可以监控节点上共存连接的数量,并延迟新连接的接受,直到该数量减少到给定阈值。但是我想了解发生了什么问题。
感谢您的帮助。
【问题讨论】:
-
在问题出现之前您获得了多少连接?
-
没有准确检查过,但我猜大概在 400-500 之间。我怀疑可能是所有打开的文件描述符都已经很忙了。但我想在这种情况下它会引发异常
-
这是开源项目吗?可以分享完整的代码吗?
-
嗨彼得,它还没有发布。但我希望它会在某个时候发生