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 进行大量通信。因此,您可以仅关闭连接并稍后重试。

    顺便说一句,如果您 SUCCESSFULLY 已到达流尾,那么read仅会向您返回-1。对于您的情况,我确定连接是在中间关闭的。

    编辑以回复OP评论



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



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

    例如,如果在异类 channel 中实现read方法,则可以选择完全忽略规范,而不在声明中引发任何异常。但是,当遇到意外行为时,此类的用户可能会付出沉重的代价,并且可能会抛弃我的实现,而转而使用更可靠的行为。

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



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

    由于框架是由人编写的,因此它们也存在错误,缺陷等。因此,可能会抛出IOException,但底层 channel 仍然可以使用的情况。不幸的是,这些条件只能在实际生产环境中用血液和胆量才能找到。这是一个示例,其中套接字抛出的IOException可以完全忽略:http://bugs.sun.com/view_bug.do?bug_id=4516760

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

    10-07 12:44
    查看更多