java - ReadableByteChannel.read()为什么会出现IOExceptions

标签 java sockets exception nio

ReadableByteChannel.read()的规范显示 -1作为流结束的结果值。此外,它还指定了 ClosedByInterruptException如果线程被中断,可能的结果。

现在我想这就是全部了——而且大部分时间都是这样。但是,有时我会得到以下信息:

java.io.IOException: Eine vorhandene Verbindung wurde vom Remotehost geschlossen
 at sun.nio.ch.SocketDispatcher.read0(Native Method)
 at sun.nio.ch.SocketDispatcher.read(SocketDispatcher.java:25)
 at sun.nio.ch.IOUtil.readIntoNativeBuffer(IOUtil.java:233)
 at sun.nio.ch.IOUtil.read(IOUtil.java:206)
 at sun.nio.ch.SocketChannelImpl.read(SocketChannelImpl.java:236)
 at ...

我不明白为什么我没有得到 -1在这种情况下。这也不是一个干净的异常(exception),因为我无法捕捉它而不捕捉任何可能的IOException .

所以这是我的问题:
  • 为什么首先抛出这个异常?
  • 假设 read 抛出的任何异常都与套接字关闭有关是否安全?
  • write() 的所有这些都一样吗? ?

  • 顺便说一句:如果我调用 SocketChannel.close()我必须调用SocketChannel.socket().close()或者这是前面所暗示的?

    谢谢,史蒂芬

    最佳答案

    有趣,但今天有人已经发布了指向 Fallacies of Distributed Computing 的链接.

    就你而言,正如一位优秀的德英翻译告诉我的 An existing connection was forcibly closed by remote host .

    当您处理 I/O,特别是 Socket I/O 时,您必须做好准备,任何 IOException 都会向您抛出。

    其中一些,例如 ClosedByInterruptException你可以聪明地处理。其他的,你可以

  • 添加 throws声明给你的方法,让调用者处理 IOExceptions
  • 将 IOExceptions 包装成特定于您的子系统的已检查异常
  • 将 IOExceptions 包装到特定于您的子系统或不特定于您的子系统的 RuntimeException
  • 记录 IOException 并继续。

  • 在任何情况下,一旦您获得 IOException,您可能无法与该 channel 进行太多通信。因此,您可以关闭连接并稍后重试。

    顺便说一句,read如果你 只会返回 -1 给你成功 到达流尾。在您的情况下,我敢肯定,连接在中途关闭。

    编辑以回复 OP 评论

    Can I prevent a channel to be interruptible?



    不,这是您正在使用的特定 channel 的属性。如果它实现了InterruptibleChannel ,那么它是可中断的,并且会在收到线程中断时关闭。 java.nio.channels.SocketChannel是可中断的

    The docs for ClosedByInterruptException state: "Checked exception received by a thread when another thread interrupts it while it is blocked in an I/O operation upon a channel." Still how can it be blocking, if it is NON-blocking IO?



    如果您查看 ReadableByteChannel.read 的规范您将看到该方法被声明为仅抛出 IOException .然后在 JavaDoc 中,它提示了该接口(interface)的标准 java.nio 实现可能会抛出什么样的特定 IOExceptions 和 unre 什么条件。这是合作编程的例子之一。接口(interface)的声明者告诉实现者他们应该如何实现方法以及在什么条件下应该抛出什么异常。

    例如,如果我在我的奇异 channel 中实现 read 方法,我可能会选择完全忽略规范并且不在声明中抛出任何异常。但是,我类(class)的用户在遇到意外行为时可能会付出沉重的代价,并且可能会放弃我的实现以支持更强大的实现。

    无论如何,我认为您对如何对 read 方法中声明的不同异常使用react感到困惑。
    首先,并非读取方法规范中的每个异常都可能被抛出。案例 ClodesByInterruptException如果您使用的是非阻塞 I/O,很可能不会被抛出。另一方面,一些实现者可能会选择在收到中断时关闭 channel ,并在您尝试读取时抛出此异常,即使您处于非阻塞 I/O 中也是如此。但你真的不应该担心这个决定,因为:
  • 您可能控制当前是否
    线程是否中断
  • 这只是另一种
    IOException,默认情况下应该
    被视为致命

  • And yes, the example IOEception is fatal, but my question is: Are they ALL?



    请记住,您的框架应该正常运行,或者在抛出任何类型的异常时正常关闭。例如,您的代码或库代码在任何时候都可能引发未经检查的(运行时)异常。只有对您的环境进行测试和更深入的了解才能告诉您哪些异常是真正致命的,哪些可以安全处理。

    因为框架是人写的,也会有bug、不足等。所以可能会有抛出IOException的情况,但是底层 channel 还是可以的。不幸的是,这些条件只能在真实的生产环境中通过血液和内脏找到。这是可以完全忽略套接字抛出的 IOException 的示例之一:http://bugs.sun.com/view_bug.do?bug_id=4516760 .

    因此,首先为所有 IOExceptions 编写通用处理程序并将它们都视为致命的,然后针对您在生产中发现的特定条件放宽它。

    关于java - ReadableByteChannel.read()为什么会出现IOExceptions,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2450084/

    相关文章:

    java - 获取传入连接的域名

    javascript - 是否有同时在 C++ 和 Javascript 中实现的高级进程间通信 API

    java - 异常后未发出 Spring 集成消息

    java - 从 BaseAdapter 的 GridView 中检索 ArrayList 值

    java - 打开 tcp InetSocketAddress 到应用程序路径(不仅仅是主机 + 端口)

    java - 在 Java 中使用 JSoup 解析 CSS

    c - getsockopt() 中的 optlen 参数

    java - Try-Catch 异常处理不提供正确的响应

    c# - LuaInterface - RegisterFunction 对象引用

    java - 当应用程序集群时在两个 JVM 之间共享数据