Откуда вы знаете все исключения, которые может выдать метод
Есть ли способ получить некоторые детали относительно аспектов безопасности исключений стандартных классов Java? В основном работая с C++ и C#, я запутался со спецификациями исключений Java, поэтому мне нужно понять, как правильно работать с исключениями.
Чтобы быть более конкретным, давайте рассмотрим ServerSocket
, Он начинает прослушивать входящие соединения, как только его объект создан. Затем вы должны использовать accept()
принять соединение (если кто-то пытается подключиться).
Если вы ранее настроили сокет сервера с setSoTimeout()
есть изменение, которое accept()
будет бросать SocketTimeoutException
потому что никто не пытался подключиться в указанный период времени. Это нормально, серверный сокет еще можно использовать, так что вы просто позвоните accept()
снова.
Но SocketTimeoutException
это не единственное, что accept()
может бросить. Что означают все остальные исключения? Если я заверну вызов accept()
с двумя предложениями поймать: для SocketTimeoutException
а также IOException
Могу ли я по-прежнему безопасно использовать связанные ServerSocket
экземпляр после того, как я попал в IOException
статья?
Я был бы очень признателен за ответы как по Java, так и по ServerSocket.
6 ответов
Повторно использовать объект небезопасно. Для такого вопроса я бы всегда искал источник, поэтому он и открыт.
Так что если вы посмотрите на это: http://kickjava.com/src/java/net/ServerSocket.java.htm вы заметите, что в accept()
SocketException (наследуется от IOException) генерируется, если сокет закрыт или больше не связан. Оба состояния указывают, что ServerSocket больше не действителен.
Так что для этого класса, как правило, если вы терпите неудачу с исключением, всегда старайтесь изящно закрыть ServerSocket в блоке finally, а затем воссоздать его.
Кроме того, в вашей общей области вопросов Java: всегда изучайте исходный код и понимайте, что делает интерфейс. Если это критически важные тесты записи, которые воспроизводят поведение (это не должно быть легко при таком низком уровне API).
Наконец, последовательно ли Java делает такие вещи? Нет. Некоторые классы не имеют состояния, другие - нет (например, ServerSocket), некоторые - поточно-ориентированные, другие - нет. И вам нужно понять - либо из документации, либо (в основном) из кода - в каком состоянии они построены, чтобы понять, что делать, когда исключение выбивает вас из основного пути.
Большинство людей проклинают эти проверенные исключения Java, потому что большинство из них (как и большинство IOException) на самом деле не могут быть восстановлены осмысленным образом. Они утверждают, что в большинстве случаев вы не можете понять каждый прекрасный случай. По этой причине многие сложные фреймворки могут повторить попытку дважды или трижды, если они думают, что в этом случае они могут, но в конце концов выдают исключение RuntimeException на верхний уровень фреймворка. Там они делают из этого что-то полезное (содержательная ошибка, предоставляющая контекст) и записывают все детали, которые у них есть, что в большинстве случаев является следом огромного стека. Отличный источник знаний, которого боятся многие разработчики.
Итак, что вы можете сделать, если вы не смогли оправиться от непроверенной проблемы в этом случае? Подбросьте (возможно, с некоторым подклассом RuntimeException) наиболее значимую трассировку стека, аннотированную всем имеющимся у вас контекстом. Настройка мониторинга. И если вы столкнетесь с частой проблемой, исправьте ее.
Да. Объект все еще существует - может быть в состоянии ошибки, в этом случае он будет выдавать другие исключения, пока это не будет исправлено.
Но SocketTimeoutException - не единственное, что может выдать accept(). Что означают все остальные исключения?
Согласно Javadoc, заявленные исключения IOException
, SecurityException
, SocketTimeoutException
а также IllegalBlockingModeException
, SecurityException
а также IllegalBlockingModeException
происходят только в определенных контекстах, и вы не должны пытаться поймать и обработать их. (Это не те проблемы, от которых вы хотите избавиться!) IOException
происходит, когда возникает "какая-то другая ошибка ввода-вывода". В javadoc не указано, какими могут быть эти ошибки ввода / вывода, но возможны такие вещи, как:
- адрес, к которому вы привязаны, больше не действителен
- произошла ошибка транспортного протокола
- произошла ошибка (проблема с ресурсом, ошибка...) в стеке протоколов ОС
(Тот факт, что Javadoc не говорит, какой IOException
Подклассы могут быть выброшены - намек на то, что вы не должны пытаться делать умные вещи, чтобы попытаться восстановиться. Если вы это сделаете, ваш код, вероятно, будет зависеть от платформы.)
Если я оберну вызов метода accept() двумя предложениями catch: для SocketTimeoutException и IOException, могу ли я по-прежнему безопасно использовать связанный экземпляр ServerSocket после того, как попал в предложение IOException?
И да и нет. Это безопасно в том смысле, что вы не переведете свое приложение в худшее состояние, чем оно уже находится. С другой стороны, нет гарантии, что следующее accept
вызов не потерпит неудачу с той же проблемой.
Если ваше приложение предназначено для запуска в качестве автоматического сервера, я не думаю, что у вас есть большой выбор, кроме как войти в систему. IOException
и попробуйте еще раз... в надежде, что проблема временная.
Я еще не нашел простой способ узнать, находится ли объект в рабочем состоянии. Каждый объект создает свои собственные правила.
В вашем конкретном случае с ServerSocket я бы попробовал одну из двух вещей:
Запустите netstat или другую утилиту, чтобы узнать, что операционная система думает о том, что делает сокет. Если ОС не думает, что слушает, значит, что-то случилось. или же
Напишите тестовую программу, которая сгенерирует исключение, и посмотрите, что он делает. Я делаю это все время (особенно с проприетарным программным обеспечением). Было бы сложнее в выбранном вами случае ServerSocket, так как все сценарии, которые я могу придумать (например, адрес в использовании, недостаточные привилегии и т. Д.), Никогда не приведут к тому, что объект будет по-прежнему действительным.
Если вы прочитаете спецификацию для ServerSocket, вы увидите, что он выдает IOException "если возникает ошибка ввода-вывода при ожидании соединения". Безопасно ли accept()
снова в розетку? Да. Собираетесь ли вы снова получить то же исключение? Скорее всего так.
Вы можете найти свой ответ на Javadoc setsoTimeout
, это говорит:
Включить / отключить SO_TIMEOUT с указанным тайм-аутом в миллисекундах. Если для этой опции задано ненулевое время ожидания, вызов метода accept() для этого ServerSocket будет блокироваться только на это время. Если время ожидания истекает, создается исключение java.net.SocketTimeoutException, хотя ServerSocket все еще действует. Эта опция должна быть включена до начала операции блокировки, чтобы иметь эффект. Тайм-аут должен быть> 0. Тайм-аут, равный нулю, интерпретируется как бесконечный тайм-аут.