为什么在ReadableByteChannel.read()中出现IOExceptions

时间:2010-03-15 20:01:59

标签: 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。这也不是一个干净的例外,因为我没有抓住任何可能的IOException来抓住它。

所以这是我的问题:

  1. 为什么首先抛出这个例外?
  2. 是否可以安全地假设read抛出的任何异常都与套接字关闭有关?
  3. write()
  4. 的所有内容是否相同?

    顺便说一句:如果我拨打SocketChannel.close(),我是否也必须拨打SocketChannel.socket().close(),或者这是否早先暗示过?

    谢谢,Steffen

2 个答案:

答案 0 :(得分:2)

很有趣,但今天有人发布了Fallacies of Distributed Computing的链接。

在您的情况下,作为一名优秀的德语译成英语的翻译员告诉我An existing connection was forcibly closed by remote host

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

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

  1. 向您的方法添加throws声明,让调用者处理IOExceptions
  2. 将IOExceptions包装到特定于子系统的已检查异常中
  3. 将IOExceptions包装到特定于或不属于您的子系统的RuntimeException中
  4. 记录IOException并继续。
  5. 在任何情况下,一旦获得IOException,您可能无法与该频道进行通信。因此,您可以关闭连接并稍后重试。

    BTW,read只有在 SUCCESSFULLY 到达流末尾时才会返回-1。在你的情况下,我确信,连接在中途关闭。

    编辑回复OP评论

      

    我可以阻止频道吗?   中断?

    不,这是您正在使用的特定频道的属性。如果它实现InterruptibleChannel,则它是可中断的,并在收到线程中断时关闭。 java.nio.channels.SocketChannel是可以中断的

      

    文档   ClosedByInterruptException状态:   “收到的检查异常   另一个线程中断时的线程   它在I / O中被阻塞   通道上的操作。“还是如何   它是否会阻塞,如果是的话   非阻塞IO?

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

    例如,如果我在异域信道中实现read方法,我可以选择完全忽略规范,而不是在声明中抛出任何异常。虽然我的班级用户在遇到意外行为时可能会付出沉重的代价,并且可能会将我的实施转移到更强大的实施中。

    无论如何,我认为你对如何应对read方法中声明的不同异常感到困惑。 首先,并非抛出读取方法规范中的每个异常。在您使用非阻塞I / O的情况下,最有可能不会抛出ClodesByInterruptException点的情况。另一方面,一些实现者可能会在收到中断时选择关闭通道,并在尝试读取时抛出此异常,即使您处于非阻塞I / O中也是如此。但你真的不应该关心这个决定,因为:

    1. 您可能会控制当前是否正常 线程中断或不中断
    2. 这只是另一种 IOException,默认情况下应该 被视为致命
    3.   

      是的,示例IOEception是   致命,但我的问题是:他们   ALL?

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

      因为框架是由人编写的,所以它们也存在缺陷,缺陷等。因此可能存在抛出IOException但底层通道仍然正常的情况。不幸的是,这些情况只能在真实生产环境中的血液和内脏中找到。下面是一个示例,其中套接字抛出的IOException可以完全忽略:http://bugs.sun.com/view_bug.do?bug_id=4516760

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

答案 1 :(得分:0)

根据文档here

  

线程收到的已检查异常   当另一个线程中断它   虽然它在I / O中被阻止   通道上的操作。在这之前   通道将抛出异常   已经关闭和中断   先前被阻止的状态   线程将被设置。

这表明拥有ReadableByteChannel的线程正被应用程序中的另一个线程中断......是这种情况吗?

如果另一个帖子关闭了频道,我希望你会看到AsynchronousCloseException

我没有看到你无法明确捕获ClosedByInterruptException并且允许在堆栈中处理更高的任何其他异常的原因:

try
{
    rbc.read(dst);
} 
catch ( ClosedByInterruptException cbie)
{
    /* handler */
}

至于write()write()没有ReadableByteChannel方法,但WritableByteChannel write()方法,它可以抛出相同的异常。

相关问题