SocketChannel的超时无效。

17

我想使用SocketChannel并为其读写方法设置超时。我尝试为拥有我的SocketChannel的套接字设置超时,如下所示:

channel.socket().setSoTimeout(TIMEOUT);

但那并不起作用。还有其他解决方案吗?


3
很遗憾,SocketChannel不支持直接使用setSoTimeout方法。尝试使用该方法将被无情地忽略。 - casey
9
SocketChannel实现了InterruptibleChannel接口,这意味着在进入read()调用之前,你可以创建一个单独的线程,并让该线程设置一个定时器。当定时器到期时,它可以中断阻塞SocketChannel read()调用的线程。如果read()调用先返回,你可以让它终止定时器线程。 - Stevens Miller
5
当频道关闭时,读取操作将抛出ClosedByInterruptException异常。这并不是很有用。据说这种奇怪的实现是受Linux行为的规定。 - user207421
3个回答

13
根据这篇文章,SocketChannel的读操作不会超时,但你可以通过其他方式从通道中读取数据来达到超时的效果。
SocketChannel socketChannel;
socketChannel.socket().setSocketTimeout(500);
InputStream inStream = socketChannel.socket().getInputStream();
ReadableByteChannel wrappedChannel = Channels.newChannel(inStream);

从wrappedChannel读取数据将会根据你设置的socketTimeOut超时。


1
这不是正确的做法,只是一个解决方法。正确的方法是在循环中使用Selector.select(timeout),并使用if-check检查soTimeout/connectTimeout。 - wzona
setSocketTimeout 现在更名为 setSoTimeout,但功能保持不变。 - Pedro Estevão

3
如果您熟悉使用Java Selector,可以使用选择器模拟套接字超时。有助于查看sun.nio.ch.SocketAdaptor。
使用Thread.interrupt()需要小心。 SocketChannel是可中断通道。当您读取InterruptibleChannel的描述时,Thread.interrupt()会导致关闭SocketChannel。 如果您想在超时后继续使用SocketChannel,则不能使用InterruptibleChannel功能。

-1

你也可以考虑将你的通道设置为非阻塞,并使用System.currentTimeMillis()。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接