如何在阻塞模式NIO中实现超时?

3
我没有使用任何选择器或其他类似的东西。我只有一个简单的ServerSocketChannel监听和一个SocketChannel以阻塞模式连接到它。我想在连接上强制设置超时时间,但是SocketChannel.socket().setSoTimeout()不起作用。
我试图让后台线程睡眠30秒,并检查变量是否仍然为null(因为它会阻塞等待读入该变量),但我无法正确同步变量,因为我无法在匿名类中访问本地变量。
还有其他方法可以实现这一点吗?
更新:我的问题表述有误。我还想在读操作以及连接本身上设置超时。

可能是在java.nio中指定连接超时的重复问题。 - ollo
1
不,那是用于非阻塞模式nio的。我在谈论阻塞模式。 - ldam
2个回答

2

setSoTimeout()方法设置的是读取超时时间,而不是连接超时时间。尽管在阻塞模式下,甚至使用包装流,但在SocketChannels上它似乎根本不起作用。

你需要寻找的方法是带有两个参数的channel.socket().connect()方法。


谢谢,但我也想在读取操作上设置超时时间。我已经更新了我的问题以反映这一点。昨晚我很累,忘记提到它了。 - ldam
我建议您使用java.net.Socket,它具有读取超时功能。 - user207421
关于setSoTimeout()SocketChannel上无法工作的最佳答案在这里,提供了一种解决方法。我尝试过并且有效。 - Sarthak Singhal

-1
据我所知,在nio中使用同步操作是不可能实现的。通过Socket.setSoTimeout()设置的套接字超时会影响读取和写入,但不会影响建立连接。
连接超时与读/写超时在系统库级别上是不同的——请参见man 2 connectman 2 setsockoptman 7 socket以获取详细信息。因此,如果您想要一个真正的、应用程序控制的连接超时,您需要使用异步连接协议和适当的Selector,检查SelectionKey.isConnectable()等等。不幸的是,这会使代码变得相当冗长。
我现在没有Java lib源代码,但是研究一下Socket.connect(SocketAddress endpoint,int timeout)内部的实现方式会很有趣——但我相信它也是在内部使用select()

你错了。你可以在阻塞模式下使用NIO,并且你可以获得读取超时和连接超时。操作员不必切换到非阻塞模式。-1 - user207421
@EJP 我并不这么认为。SocketChannelImpl.connect() 的代码使用的是 Net.connect(),它没有传递任何超时值。如果您使用 SocketChannel.socket(),您会得到一个 SocketAdaptor 实例,它的 connect() 方法 在内部使用异步 I/O。因此,SO_TIMEOUT 似乎对 SocketChannel.connect() 没有影响。 - Michał Kosmulski
调用 channel.socket.connect(address, timeout) 方法,如果连接超时,则会像字面意思一样返回一个连接超时的错误。我并没有提到 SO_TIMEOUT。 - user207421
如果您调用SocketChannel.socket().connect(address,timeout),实际上您正在使用普通的Socket API - 因此我不会将其称为使用nio连接的示例,这是我理解的OP所需的。 - Michał Kosmulski
3
他需要的是从NIO API开始获取连接超时的方法,这就是方法。他不需要任何形式的“NIO API纯度”,也不需要在非阻塞模式下自己实现定时连接和选择器,因为底层已经有一行代码可以完美地实现这一点。 - user207421

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