我的服务器有问题,星期五早上我收到了以下IOException:
11/Sep/2015 01:51:39,524 [ERROR] [Thread-1] - ServerRunnable: IOException:
java.io.IOException: Too many open files
at sun.nio.ch.ServerSocketChannelImpl.accept0(Native Method) ~[?:1.7.0_75]
at sun.nio.ch.ServerSocketChannelImpl.accept(ServerSocketChannelImpl.java:241) ~[?:1.7.0_75]
at com.watersprint.deviceapi.server.ServerRunnable.acceptConnection(ServerRunnable.java:162) [rsrc:./:?]
at com.watersprint.deviceapi.server.ServerRunnable.run(ServerRunnable.java:121) [rsrc:./:?]
at java.lang.Thread.run(Thread.java:745) [?:1.7.0_75]
ServerRunnable类的第162行在下面的方法中,它是ssc.accept()
调用。
private void acceptConnection(Selector selector, SelectionKey key) {
try {
ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
SocketChannel sc = ssc.accept();
socketConnectionCount++;
/*
* Test to force device error, for debugging purposes
*/
if (brokenSocket
&& (socketConnectionCount % brokenSocketNumber == 0)) {
sc.close();
} else {
sc.configureBlocking(false);
log.debug("*************************************************");
log.debug("Selector Thread: Client accepted from "
+ sc.getRemoteAddress());
SelectionKey newKey = sc.register(selector,
SelectionKey.OP_READ);
ClientStateMachine clientState = new ClientStateMachine();
clientState.setIpAddress(sc.getRemoteAddress().toString());
clientState.attachSelector(selector);
clientState.attachSocketChannel(sc);
newKey.attach(clientState);
}
} catch (ClosedChannelException e) {
log.error("ClosedChannelException: ", e);
ClientStateMachine clientState = (ClientStateMachine)key.attachment();
database.insertFailedCommunication(clientState.getDeviceId(),
clientState.getIpAddress(),
clientState.getReceivedString(), e.toString());
key.cancel();
} catch (IOException e) {
log.error("IOException: ", e);
}
}
我应该如何处理?阅读错误,它似乎是Linux操作系统中的一个设置,它限制了进程可以拥有的打开文件的数量。 从那以及this question here来看,似乎我没有正确关闭套接字(服务器当前正在为大约50个客户端提供服务)。这是一种情况,我需要一个计时器来监视打开的套接字并在一段时间后将它们计时?
在某些情况下,客户端可以连接,然后在建立连接后不发送任何数据。我以为我已经妥善处理了这些案件。
我的理解是,非阻塞的NIO服务器有很长的超时时间,如果我错过了这样的情况,它们可能会累积并导致此错误吗?
此服务器已运行三个月,没有任何问题。 在我查看代码并检查处理不当/丢失的情况后,处理此特定错误的最佳方法是什么?我还应该考虑其他可能有助于此的事情吗?
另外,(也许这应该是另一个问题)我有log4j2配置为发送错误和更高的日志级别的电子邮件,但我没有收到此错误的电子邮件。有什么理由可以吗?它通常工作,错误被记录到日志文件中,但我从未收到有关它的电子邮件。每次建立连接时都会发生错误,我应该已经充足了。
答案 0 :(得分:2)
您修复了套接字泄漏。当您在套接字上获得EOS或IOException
以外的任何SocketTimeoutException,
时,您必须将其关闭。在SocketChannels,
的情况下,这意味着关闭频道。仅仅取消关键,或忽略问题并希望它会消失,是不够的。连接已经消失。
您发现有必要计算损坏的套接字连接,并且捕获ClosedChannelException,
已经表明您的应用程序中存在严重的逻辑问题。你不应该需要这个。取消封闭渠道的密钥并不能提供任何解决方案。
我的理解是,非阻塞的NIO服务器有很长的超时时间
非阻塞NIO服务器唯一的超时是您为select()
指定的超时。内置于TCP堆栈的所有超时都不受您使用NIO还是非阻塞模式的影响。