如何在 Java 1.4 中设置 BufferedReader 和 PrintWriter 的超时时间?
Posted
技术标签:
【中文标题】如何在 Java 1.4 中设置 BufferedReader 和 PrintWriter 的超时时间?【英文标题】:How do you set a timeout on BufferedReader and PrintWriter in Java 1.4? 【发布时间】:2011-10-11 04:37:46 【问题描述】:如何在使用套接字连接创建的 BufferedReader 和 PrintWriter 上设置超时?这是我现在为服务器提供的代码,它可以在服务器或客户端崩溃之前工作:
while(isReceiving)
str = null;
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintWriter pw = new PrintWriter(socket.getOutputStream(), true);
while ((str = br.readLine()) != null)
System.out.println("Processing command " + str);
pw.println(client.message(str));
在此代码范围之外,我设置了 1000 毫秒的套接字超时,这在等待初始连接时按预期工作。但是程序在 (str = br.readLine()) 处阻塞。如果客户端挂起或崩溃,它永远不会停止阻塞,除非我终止进程(即使那样并不总是有效)。
有问题的客户端代码与此非常相似,并且以类似的方式阻塞。
【问题讨论】:
【参考方案1】:您需要在套接字上设置读取超时,使用Socket.setSoTimeout()
。如果指定的读取超时到期,这将导致任何读取方法抛出SocketTimeoutException
。注意 读取超时不是在流上设置的,而是在底层Socket,
通过Socket.setSoTimeout().
TCP 中不存在写超时。
【讨论】:
在上面我发布了我的解决方法以在我的情况下获得所需的行为,但在这种情况下没有办法停止阻止?正如我的问题所述,我在我发布的内容之外调用了 socket.setSoTimeout(1000L),所以套接字不应该在此时超时并结束套接字上的所有读写操作吗? @MetalSearGolid 它应该结束读取操作,并在读取阻塞超时时间后出现 SocketTimeoutException。正如我已经说过的,TCP 中没有写超时。 @YoussefDir 这设置了读取超时,正如我在答案中所述。不是写超时,【参考方案2】:您可以使用来自 Google 的 Guava 库的 SimpleTimeLimiter。
示例代码(在 Java 8 中):
BufferedReader br = ...;
TimeLimiter timeLimiter = new SimpleTimeLimiter();
try
String line = timeLimiter.callWithTimeout(br::readLine, 10, TimeUnit.SECONDS);
catch (TimeoutException | UncheckedTimeoutException e)
// timed out
catch (Exception e)
// something bad happened while reading the line
【讨论】:
发布的链接已失效,您现在可以在github.com/google/guava/tree/master/guava/src/com/google/common/…找到该项目 更新了我的答案。谢谢! ...Java 8。问题说Java 1.4。 所描述的原理将在 Java 1.4 中完美运行——唯一的区别是语法。 Guava 代码仅在相关的read()
方法是可中断的情况下才有效。 java.net.Socket
读取不是。【参考方案3】:
question 中的答案描述了一个有趣的方法,使用 Timer
来关闭连接。我不能 100% 确定这在阅读过程中是否有效,但值得一试。
从那个答案复制:
TimerTask ft = new TimerTask()
public void run()
if (!isFinished)
socket.close();
;
(new Timer()).schedule(ft, timeout);
isFinished
应该是一个 boolean
变量,当您从流中读取完毕后,该变量应该设置为 true
。
【讨论】:
+1:我会使用 socket.close() 来关闭套接字和流。您可以多次关闭它。 您也可以说出isFinished
测试的用途。 ;)
我会试一试,但我怀疑 socket.close() 是否会起作用,因为我已经尝试过以这种方式关闭它......没有骰子。我要关闭的套接字是否在另一个线程中应该没关系吗?
这不起作用,即使在我关闭套接字后 br.readLine() 仍然会继续阻塞。不过,我确实找到了解决方法,我会尽快将其作为答案发布。
@BendertheGreatest 不可能。你会得到一个socket closed
异常。【参考方案4】:
由于调用 socket.close() 似乎没有中断 br.readLine() 处的块,所以我做了一些解决方法。在断开客户端与服务器的连接时,我只是通过一个字符串“bye”发送,并告诉服务器在收到此命令时关闭套接字连接。
while ((str = br.readLine()) != null)
// If we receive a command of "bye" the RemoteControl is instructing
// the RemoteReceiver to close the connection.
if (str.equalsIgnoreCase("bye"))
socket.close();
break;
System.out.println("Processing command " + str);
pw.println(client.message(str));
【讨论】:
如果你可以发送“再见”,你可以直接关闭套接字,这将导致对端的readLine()
返回 null。很难看出这如何解决您所说的问题。
我问这个问题已经有一段时间了,但是如果内存服务于从客户端关闭套接字后监听进程继续挂起。我记得我们使用了一些伪善的 Java 自定义实现,但它的行为并不总是像人们预期的那样。
你所说的不可能。请重新测试。以上是关于如何在 Java 1.4 中设置 BufferedReader 和 PrintWriter 的超时时间?的主要内容,如果未能解决你的问题,请参考以下文章