9

我有一个由 OutputStream 和 InputStream 组成的通用套接字实现。

完成一些工作后,我将关闭 OutputStream。

完成此操作后,我的 InputStream 的 read() 方法在无限时间内返回 -1,而不是像我预期的那样抛出异常。

我现在不确定最安全的路线,所以我有几个问题:

  • 我可以安全地假设 -1 仅在流关闭时返回吗?
  • 有没有办法重新创建连接被强行断开时发生的IO异常?
  • 我是否应该发送一个数据包来告诉我的 InputStream 它应该关闭而不是前两种方法?

谢谢!

4

5 回答 5

7

-1 是流结束时的预期行为。见InputStream.read()

从输入流中读取数据的下一个字节。值字节作为 int 返回,范围为 0 到 255。如果由于到达流的末尾而没有可用的字节,则返回值 -1。此方法会一直阻塞,直到输入数据可用、检测到流结束或引发异常。

当然,您仍然应该捕捉IOException意外事件。

于 2011-04-10T02:10:42.590 回答
2

我可以安全地假设 -1 仅在流关闭时返回吗?

是的。

你不应该假设这样的事情。您应该阅读 javadoc 并根据 API 的指定行为方式进行实施。特别是如果您希望您的代码健壮(或如您所说的“安全”。)

话虽如此,这或多或少是javadoc在这种情况下所说的(有人可能会狡辩说 EOF 和“流已关闭”不一定意味着同一件事......并且通过调用InputStream.close()Socket.close() 本地关闭流会产生不同的效果。但是,这些都与您的使用没有直接关系-案子。)

有没有办法重新创建连接被强行断开时发生的IO异常?

不。首先,通常不会首先抛出异常,因此通常没有什么可以“重新创建”。其次,原始异常中的信息(如果有的话)已经消失了。

我是否应该发送一个数据包来告诉我的 InputStream 它应该关闭而不是前两种方法?

不,最好的方法是测试read调用的结果。无论如何,您都需要对其进行测试,因为您不能假设该read(byte[])方法(或其他方法)将返回您实际要求的字节数。

我想在某些情况下抛出一个特定于应用程序的异常是可以的。

但请记住一般原则,异常不应用于正常的流控制。


其他答案之一建议创建一个代理 InputStream 抛出一些异常而不是返回-1。

IMO,这是个坏主意。您最终会得到一个声称是 的代理类InputStream,但违反了read方法的约定。如果代理被传递给期望正确实现的东西,这可能会导致麻烦InputStream

其次,InputStreamis an abstract classnot an interface,所以 Java 的动态代理机制不起作用。(例如,该newProxyInstance方法需要一个接口列表,而不是类。)

于 2011-04-10T02:30:42.233 回答
0

根据InputStreamjavadoc,read()返回:

数据的下一个字节,如果到达流的末尾,则为 -1。

因此,您可以放心地假设,最好使用 API 中指定的内容,而不是尝试重新创建异常,因为抛出的异常可能取决于实现。

于 2011-04-10T02:12:37.780 回答
0

此外,关闭套接字中的输出流也会关闭套接字本身。

这就是 Socket 的 JavaDoc 所说的:

公共输出流 getOutputStream() 抛出 IOException

Returns an output stream for this socket.

If this socket has an associated channel then the resulting output

流将其所有操作委托给通道。如果通道处于非阻塞模式,则输出流的写入操作将引发 IllegalBlockingModeException。

Closing the returned OutputStream will close the associated socket.

Returns:
    an output stream for writing bytes to this socket. 
Throws:
    IOException - if an I/O error occurs when creating the output stream

或者如果套接字未连接。

不确定这是否是您真正想要做的。

于 2011-04-10T02:22:39.293 回答
-1

有没有办法重新创建连接被强行断开时发生的IO异常?

我会回答这个。InputStream 只是一个接口。如果您真的希望实现在 EOF 上引发异常,请提供您自己的小型包装器,覆盖 read()s 并在 -1 结果上引发异常。

最简单(最少编码)的方法是使用动态代理:

InputStream pxy = (InputStream) java.lang.reflect.Proxy.newProxyInstance(
    obj.getClass().getClassLoader(),
    new Class[]{ InputStream.class },
    new ThrowOnEOFProxy(obj));

其中 ThrowOnEOFProxy 将检查方法名称,调用它,如果结果为 -1,则抛出 IOException("EOF")。

于 2011-04-10T02:24:21.390 回答