我遇到了与此处所述类似的问题:Java Linux Nonblocking Socket Timeout Behavior
我有一个用 Java NIO 实现的应用程序。它跟踪一堆套接字,当它们准备好读取时,我的应用程序将循环读取(删除代码和一些简洁的逻辑):
if (selkey.isReadable()) {
int nread;
while (true) {
// read the header
nread = mSocketChannel.read(mHeaderBuffer);
if (nread == -1)
return;
handle_message_header();
// read the body
nread = mSocketChannel.read(mPayloadBuffer);
if (nread == -1)
return;
handle_message_body();
}
}
但是在第一次 read() 中我很少收到超时异常:
java.io.IOException: Connection timed out
at sun.nio.ch.FileDispatcher.read0(Native Method)
at sun.nio.ch.SocketDispatcher.read(SocketDispatcher.java:21)
at sun.nio.ch.IOUtil.readIntoNativeBuffer(IOUtil.java:202)
at sun.nio.ch.IOUtil.read(IOUtil.java:175)
at sun.nio.ch.SocketChannelImpl.read(SocketChannelImpl.java:243)
我深入研究了 jdk 源代码,read0 函数只是在套接字句柄上调用 read()。如果 read() 返回 -1 并且 errno == ETIMEDOUT,则会引发“连接超时”异常。
我们不使用 soSetTimeout() 或 tcp keepalive 选项。而且由于我只在客户端的集群上看到它,所以我无法重现它(我也没有 netstat 或其他工具的输出)。
我想知道 linux 内核在哪些情况下会在非阻塞 read() 中返回 ETIMEDOUT?这是错误还是功能?
有关出现此问题的机器的更多信息:
Linux slave1 2.6.18-164.e15 #1 SMP Thu Sep 3 03:28:30 EDT 2009 x86_64 x86_64 x86_64 GNU/Linux
CentOS 5.4
谢谢克里斯
编辑:根据我的日志文件(和程序流程),套接字是在服务器接受传入连接时创建的。然后从那个套接字至少有一个成功的recv,但是服务器两次写入失败。然后我在阅读时发现了异常。日志文件没有太多信息——因此,到目前为止,我对我的分析并不是 100% 确定的。我已经为套接字例程添加了很多调试输出,现在我为下一次做好了更好的准备。
感谢所有有用的评论!