Почему возникают исключения IOException в ReadableByteChannel.read () - PullRequest
2 голосов
/ 15 марта 2010

Спецификация 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. Можно ли предположить, что ЛЮБОЕ исключение, выдаваемое чтением, касается закрытия сокета?
  3. Это все то же самое для write()?

И, кстати: если я звоню SocketChannel.close(), должен ли я также звонить SocketChannel.socket().close() или это подразумевается ранее?

Спасибо, Штеффен

Ответы [ 2 ]

2 голосов
/ 15 марта 2010

Забавно, но кто-то сегодня уже разместил ссылку на Заблуждения распределенных вычислений .

В вашем случае, как говорит мне хороший переводчик с немецкого на английский An existing connection was forcibly closed by remote host.

Когда вы имеете дело с вводом / выводом, в частности с сокетным вводом / выводом, вы должны быть готовы к тому, что любое исключение IOException будет выдано вам.

С некоторыми из них, например ClosedByInterruptException, вы можете справиться с умом. Другие, вы можете

  1. Добавьте throws декларации к вашему методу и разрешите вызывающим объектам работать с IOExceptions
  2. Обернуть исключения IOException в проверенное исключение, специфичное для вашей подсистемы
  3. Обернуть IOException в RuntimeException, специфичную для вашей подсистемы или нет
  4. Записать IOException и продолжить.

В любом случае, как только вы получите IOException, вы, вероятно, не сможете многое сделать для связи с этим каналом. Так что вы можете просто закрыть соединение и повторить попытку позже.

Кстати, read вернет вам -1, только если вы SUCCESSFULLY достигли конца потока. В вашем случае, я уверен, соединение в середине потока закрыто.

РЕДАКТИРОВАТЬ в ответ на комментарии OP

Могу ли я запретить каналу быть прерываемые

Нет, это свойство определенного канала, который вы используете. Если он реализует InterruptibleChannel, то он прерывается и будет закрыт при получении прерывания потока. java.nio.channels.SocketChannel прерывается

Документы для Состояние ClosedByInterruptException: «Проверено исключение, полученное поток, когда другой поток прерывает это пока он заблокирован в I / O операция на канале. "Еще как это может быть блокировка, если это НЕБЛОКИРУЮЩИЙ IO?

Если вы посмотрите на спецификацию ReadableByteChannel.read, вы увидите, что метод объявлен как бросающий IOException. Затем в JavaDoc он указывает, какие конкретные исключения IOException и какие условия могут быть вызваны стандартной реализацией этого интерфейса java.nio. Это один из примеров совместного программирования. Декларатор интерфейса сообщает разработчику, как он должен реализовать метод и какие исключения он должен генерировать при каких условиях.

Например, если я реализую метод read в своем экзотическом канале, я могу выбрать полное игнорирование спецификации и не выбрасывать исключения в объявлении. Пользователь моего класса, тем не менее, вероятно, заплатит высокую цену, столкнувшись с неожиданным поведением, и, вероятно, откажется от моей реализации в пользу более надежной.

В любом случае, я думаю, вы не понимаете, как следует реагировать на различные исключения, объявленные в методе чтения. Прежде всего, не каждое исключение в спецификации метода чтения может быть выброшено. Пример ClodesByInterruptException, скорее всего, НЕ будет сброшен, если вы используете неблокирующий ввод / вывод. С другой стороны, некоторые разработчики могут выбрать закрытие канала после получения прерывания и выдать это исключение при попытке чтения, даже если вы используете неблокирующий ввод / вывод. Но вы действительно не должны связываться с этим решением, потому что:

  1. Вы, вероятно, контролируете ли ток нить прервана или нет
  2. Это просто другой вид IOException, и по умолчанию должен быть фатальным

И да, пример IOEception фатальный, но мой вопрос: они ALL

Помните, что ваш фреймворк должен нормально функционировать или корректно завершаться при возникновении любых исключений. Например, ваш код или код библиотеки в любой момент может вызвать исключение без проверки (время выполнения). Только тестирование и более глубокое знание вашей среды могут сказать вам, какие исключения действительно фатальны, а какие можно безопасно обработать.

Поскольку фреймворки написаны людьми, у них также есть ошибки, недостатки и т. Д. Таким образом, может быть случай, когда выбрасывается IOException, но основной канал все еще в порядке. К сожалению, эти условия можно найти только с кровью и кишками в реальной производственной среде. Вот один из примеров, где IOException, генерируемое сокетом, может быть полностью проигнорировано: http://bugs.sun.com/view_bug.do?bug_id=4516760.

Итак, начните с написания универсального обработчика для всех исключений IOException и отнеситесь к ним как к фатальным, ослабьте его для определенных условий, которые вы обнаружите в рабочей среде.

0 голосов
/ 15 марта 2010

Согласно документации здесь :

Проверено исключение, полученное потоком когда другой поток прерывает его в то время как это заблокировано в I / O операция на канале. До этого исключение брошено канал будет были закрыты и прерывание статус ранее заблокированного нить будет установлена.

Это говорит о том, что поток, которому принадлежит ReadableByteChannel, прерывается другим потоком в вашем приложении ... это так?

Если бы другой поток закрывал канал, я ожидал бы, что вы увидите AsynchronousCloseException.

Я не вижу причины, по которой вы не можете явно перехватить ClosedByInterruptException и разрешить обработку любых других исключений выше по стеку:

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

Что касается write(), то для ReadableByteChannel нет метода write(), однако, WritableByteChannel, имеет метод write() и может бросить те же исключения.

...