如何在阻塞模式 NIO 中实现超时?
Posted
技术标签:
【中文标题】如何在阻塞模式 NIO 中实现超时?【英文标题】:How does one implement a timeout in blocking mode NIO? 【发布时间】:2013-02-13 17:58:10 【问题描述】:我没有使用任何选择器或类似的东西。我只有一个简单的ServerSocketChannel
监听和一个SocketChannel
以阻塞模式连接到它。我想对连接施加超时,但SocketChannel.socket().setSoTimeout()
不起作用。
我尝试让后台线程休眠 30 秒并检查变量是否仍然是 null
(因为它会阻止等待读取该变量)但我无法正确同步变量,因为我无法访问我的匿名类中的局部变量。
还有其他方法可以做到这一点吗?
更新:我的问题措辞有误。我还希望读取操作以及连接本身超时。
【问题讨论】:
Specify connection timeout in java.nio 的可能重复项 不,那是用于非阻塞模式的 nio。我说的是阻塞模式。 【参考方案1】:setSoTimeout()
设置读取超时,而不是连接超时,并且由于某种原因,它在 SocketChannels
上根本不起作用,即使在阻塞模式下,甚至在包装流的情况下也是如此。
您要查找的方法是 channel.socket().connect()
,带有两个参数。
【讨论】:
谢谢,但我也希望读取操作超时。我也更新了我的问题以反映这一点。昨晚累的时候问的,忘记提了。 那我建议你使用java.net.Socket
,它确实有读取超时。
关于setSoTimeout()
不能在SocketChannel
上工作的最佳答案是here,有一个解决方法。试过了,对我有用。【参考方案2】:
据我所知,在nio
中使用同步操作是不可能的。通过Socket.setSoTimeout()
设置的套接字超时会影响读写,但不会建立连接。
即使在系统库级别,连接超时也不同于读/写超时 - 请参阅 man 2 connect
、man 2 setsockopt
和 man 7 socket
了解详细信息。所以如果你想要连接时真正的、应用程序控制的超时,你需要使用异步连接协议和适当的Selector
,检查SelectionKey.isConnectable()
等等。不幸的是,这会使代码变得更长。
我现在手头没有 Java 库源,但是看看 Socket.connect(SocketAddress endpoint,int timeout)
是如何在内部实现的会很有趣 - 但我相信它也在内部使用 select()
。
【讨论】:
你错了。您可以在阻塞模式下使用 NIO,并且可以获得读取超时和连接超时。 OP 不必切换到非阻塞模式。 -1 @EJP 我不这么认为。 SocketChannelImpl.connect() 的代码使用Net.connect()
,它没有传递任何超时值。如果你使用SocketChannel.socket()
,你会得到一个SocketAdaptor
的实例,它的connect() method 在内部使用异步I/O。所以 SO_TIMEOUT 似乎不会影响 SocketChannel.connect()。
调用 channel.socket.connect(address, timeout) 你会得到一个连接超时,就像它在锡上说的那样。关于 SO_TIMEOUT 我什么都没说。
如果您调用SocketChannel.socket().connect(address,timeout)
,您实际上使用的是普通的旧Socket
API - 所以我不会将此称为使用nio
连接的示例,我理解OP 的需求。
他需要的是一种从 NIO API 开始获取连接超时的方法,这就是方法。他“不需要”任何类型的“NIO API 纯度”,并且当已经有一个已经完全可以做到的单线器时,他也“不需要”用非阻塞模式和选择器实现定时连接在引擎盖下。以上是关于如何在阻塞模式 NIO 中实现超时?的主要内容,如果未能解决你的问题,请参考以下文章