Java обнаруживает закрытый поток - PullRequest
8 голосов
/ 10 апреля 2011

У меня есть общая реализация сокетов, состоящая из OutputStream и InputStream.

После того, как я сделаю некоторую работу, я закрываю OutputStream.

Когда это будет сделано, мой InputStream будет читать) метод возвращает -1 в течение бесконечного промежутка времени, вместо того чтобы генерировать исключение, как я ожидал.

Теперь я не уверен в том, какой самый безопасный путь выбрать, поэтому у меня есть несколько вопросов:

  • Можно ли предположить, что -1 возвращается только при закрытом потоке?
  • Нет ли способа воссоздать исключение ввода-вывода, которое возникает, когда соединение принудительно разорвано?
  • Должен ли я отправить пакет, который сообщит моему InputStream, что он должен закрыться вместо двух предыдущих методов?

Спасибо!

Ответы [ 5 ]

7 голосов
/ 10 апреля 2011

-1 - ожидаемое поведение в конце потока. См. InputStream.read():

Считывает следующий байт данных из входного потока. Байт значения возвращается в виде целого числа в диапазоне от 0 до 255. Если байт недоступен, поскольку достигнут конец потока, возвращается значение -1. ​​ Этот метод блокируется, пока входные данные доступно, конец потока обнаружен или сгенерировано исключение.

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

2 голосов
/ 10 апреля 2011

Могу ли я предположить, что -1 возвращается только тогда, когда поток закрыт?

Да.

Вы не должны предполагать, что такие вещи . Вы должны прочитать javadoc и реализовать в соответствии с тем, как API работает. Особенно, если вы хотите, чтобы ваш код был надежным (или «безопасным», как вы его выразили).

Сказав это, это является более или менее тем, что в данном случае говорит Javadoc. (Можно придумать, что EOF и «поток был закрыт» не обязательно означают одно и то же ... и что закрытие потока путем вызова InputStream.close() или Socket.close() локально будет иметь другой эффект Однако ни один из них не имеет прямого отношения к вашему варианту использования.)

Нет ли способа воссоздать исключение ввода-вывода, которое возникает при принудительном разрыве соединения?

Нет. Для начала, обычно не создается исключение, поэтому «воссоздать» обычно нечего. Во-вторых, информация в исходном исключении (если когда-либо было) исчезла.

Должен ли я отправить пакет, который сообщит моему InputStream, что он должен закрыться вместо двух предыдущих методов?

Нет. Лучший способ - проверить результат вызова read. В любом случае вам необходимо проверить его, поскольку вы не можете предполагать, что метод read(byte[]) (или любой другой) вернет количество байтов, которое вы фактически запросили.

Полагаю, что при определенных обстоятельствах было бы нормально создать исключение для приложения .

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


Один из других ответов предлагает создать прокси InputStream, который выдает какое-то исключение вместо возврата -1.

ИМО, это плохая идея. В итоге вы получаете прокси-класс, который утверждает, что является InputStream, но нарушает контракт методов read. Это может привести к проблемам, если прокси-сервер будет передан для чего-то, что ожидало правильно реализованного InputStream.

Во-вторых, InputStream - это abstract class, а не interface, поэтому механизм динамического прокси в Java не будет работать. (Например, метод newProxyInstance требует список интерфейсов, а не классов.)

0 голосов
/ 10 апреля 2011

Нет ли способа воссоздать исключение ввода-вывода, которое возникает при принудительном разрыве соединения?

Я отвечу на это.InputStream - это только интерфейс.Если вы действительно хотите, чтобы реализация генерировала исключение в EOF, предоставьте свою собственную маленькую оболочку, переопределите read () и сгенерируйте исключение для результата -1.

Самый простой (наименьший код) способ заключается в использованииДинамический прокси:

InputStream pxy = (InputStream) java.lang.reflect.Proxy.newProxyInstance(
    obj.getClass().getClassLoader(),
    new Class[]{ InputStream.class },
    new ThrowOnEOFProxy(obj));

, где ThrowOnEOFProxy будет проверять имя метода, вызывать его и, если результат равен -1, генерировать IOException ("EOF").

0 голосов
/ 10 апреля 2011

Кроме того, закрытие потока выходных данных в сокете закрывает сам сокет.

Вот что говорит JavaDoc для Socket:

public OutputStream getOutputStream () создает IOException

Returns an output stream for this socket.

If this socket has an associated channel then the resulting output

stream делегирует все свои операции каналуЕсли канал находится в неблокирующем режиме, то операции записи выходного потока вызовут исключение IllegalBlockingModeException.

Closing the returned OutputStream will close the associated socket.

Returns:
    an output stream for writing bytes to this socket. 
Throws:
    IOException - if an I/O error occurs when creating the output stream

или сокет не подключен.

Не уверен, что этоэто то, что вы на самом деле хотите сделать.

0 голосов
/ 10 апреля 2011

Согласно InputStream javadoc, read() возвращает:

следующий байт данных или -1, если достигнут конец потока.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...