Java NIO: Что такое IOException: Сломанная труба означает?

Для некоторых моих соединений Java NIO, когда у меня есть вызов SocketChannel.write(ByteBuffer), он выдает IOException: "Сломанная труба".

Что вызывает "сломанную трубу", и, что еще более важно, можно ли оправиться от этого состояния? Если он не может быть восстановлен, похоже, это будет хорошим признаком того, что возникла необратимая проблема, и я должен просто закрыть это соединение сокета. Это разумное предположение? Есть ли когда-нибудь время, когда этот IOException будет возникать, когда соединение сокета все еще правильно подключено (а не рабочее соединение, которое не сработало в какой-то момент)?

На стороне примечания, разумно ли всегда вызывать SocketChannel.isConnected() перед попыткой SocketChannel.write(), и если да, могу ли я также предположить, что соединение "сломан" и должно быть закрыто, если оба SocketChannel.isConnected() и SocketChannel.isConnectionPending() являются false?

Спасибо!

Ответ 1

Что вызывает "сломанную трубу" и, что более важно, возможно ли восстановление из этого состояния?

Это вызвано тем, что соединение закрывается. (Не ваше приложение закрыло соединение: это привело бы к другому исключению.)

Невозможно восстановить соединение. Вам нужно открыть новый.

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

Да, это. Как только вы получите это исключение, сокет больше не будет работать. Закрытие это единственная разумная вещь, которую нужно сделать.

Случалось ли когда-либо возникать это IOException, когда соединение с сокетом все еще правильно подключалось (а не работающее соединение, которое в какой-то момент прервалось)?

Нет. (Или, по крайней мере, не нарушая правильного поведения сетевого стека ОС, JVM и/или вашего приложения.)


Разумно ли всегда вызывать SocketChannel.isConnected() перед попыткой SocketChannel.write()...

В общем, плохая идея вызывать r.isXYZ() перед вызовом, который использует (внешний) ресурс r. Существует небольшая вероятность того, что состояние ресурса изменится между двумя вызовами. Лучше выполнить действие, перехватить IOException (или что-то еще), возникшее в результате неудачного действия, и предпринять все необходимые корректирующие действия.

В этом конкретном случае вызов isConnected() имеет смысла. Метод определен так, чтобы возвращать true если сокет был подключен в какой-то момент в прошлом. Это не говорит вам, если связь все еще жива. Единственный способ определить, живо ли соединение, это попытаться использовать его; например, читать или писать.

Ответ 2

Сломанная трубка просто означает, что соединение не выполнено. Разумно предположить, что это невозможно восстановить, а затем выполнить любые необходимые действия по очистке (закрытие соединений и т.д.). Я не верю, что вы когда-нибудь увидите это просто из-за того, что соединение еще не завершено.

Если вы используете неблокирующий режим, то метод SocketChannel.connect вернет false, и вам нужно будет использовать методы isConnectionPending и finishConnect, чтобы убедиться, что соединение завершено. Я обычно кодировал бы на основе ожиданий, что все будет работать, а затем поймать исключения, чтобы обнаружить отказ, вместо того, чтобы полагаться на частые вызовы на "isConnected".

Ответ 3

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

isConnected() не обнаруживает это условие. Только запись делает.

разумно всегда вызывать SocketChannel.isConnected() перед попыткой SocketChannel.write()

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

Ответ 4

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

Вы можете использовать isConnected(), чтобы определить, подключен ли SocketChannel или нет, но это может измениться до завершения вызова write(). Попробуйте вызвать его в своем блоке catch, чтобы убедиться, что на самом деле именно поэтому вы получаете исключение IOException.