Java SocketChannel не обнаруживает отключение?

У меня есть сокет, использующий селекторы. Я пытаюсь проверить, подключен ли мой сокет к серверу или нет.

Boolean connected = _channel.isConnected();

и он всегда возвращает true. Я отключил аэропорт (подключение к Интернету) на своем компьютере, и когда я проверяю, подключен ли сокет или нет, он все равно возвращает true. Есть идеи, почему? Я пытаюсь записывать данные на сервер каждые 3 секунды, и он по-прежнему не меняет состояние моего сокета на отключенное.


person aryaxt    schedule 14.08.2010    source источник
comment
Я запутался, кто-то продолжает менять название моих вопросов. Что тут происходит?   -  person aryaxt    schedule 15.08.2010
comment
С помощью приведенного выше кода вы проверяете, подключен ли SocketChannel. Итак, что именно вы тестировали, Socket, как указано в вашем вопросе, или канал, как описано в заголовке и показано в коде? Просто спрашиваю, потому что люди начали минусовать мой ответ... (без объяснения причин...)   -  person Andreas Dolk    schedule 16.08.2010
comment
1- Вы вручную закрываете сокет, вызывая метод, поэтому вы получаете false после отключения от сервера, в моем случае я пытаюсь определить, была ли проблема с отключением, например, потеря соединения, поэтому сокет выиграл не обнаружу, что он отключен, если я не попытаюсь отправить сообщение на сервер и не получу исключение. 2- Я также упомянул, что использую селектор. поэтому метод isConnected не показывает, подключен ли я к серверу или нет, но он показывает, подключен ли мой сокет к селектору или нет, что возвращает true, пока мой сокет подключен к селектору   -  person aryaxt    schedule 17.08.2010


Ответы (3)


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

Однако в более общем случае мы не можем быть уверены, что пакет доставлен. В java (вероятно, и в C) нет возможности проверить, подтвержден ли пакет ACK.

Даже если мы сможем проверить TCP ACK, это не гарантирует, что сервер или обработал пакет. Это означает только то, что целевая машина получила пакет и буферизировала его в памяти. После этого многое может пойти не так.

Поэтому, если вы действительно хотите быть уверены, вы не можете полагаться на транспортный протокол. У вас должен быть ACK уровня приложения, то есть серверное приложение записывает обратно сообщение ACK после того, как оно и обработало сообщение от клиента.

С точки зрения клиента, он пишет сообщение на сервер, а затем пытается прочитать ACK с сервера. Если он его получает, он может быть уверен, что его сообщение получено и обработано. Если он не может получить ACK, значит, он понятия не имеет, что произошло. Опытным путем, скорее всего, произошел сбой TCP. Следующая возможность заключается в том, что сервер рухнул. Также возможно, что все прошло нормально, за исключением того, что ACK не смог дойти до клиента.

person irreputable    schedule 14.08.2010

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

Канал не закрывается, когда сервер больше не доступен из-за разрыва физического соединения или сбоя сервера. Таким образом, как только соединение будет установлено, isConnected() будет возвращать true до тех пор, пока вы не закроете канал на своей стороне.

Если вы хотите проверить, доступен ли сервер, отправьте байт в выходной поток сокетов. Если вы получаете исключение, то сервер недоступен (соединение потеряно).


Изменить

для EJP - некоторый код для проверки и пересмотра вашего комментария и ответа:

public class ChannelTest {
     public static void main(String[] args) throws UnknownHostException, IOException {
      Socket google = new Socket(InetAddress.getByName("www.google.com"), 80);
      SocketChannel channel = SocketChannel.open(google.getRemoteSocketAddress());
      System.out.println(channel.isConnected());
      channel.close();
      System.out.println(channel.isConnected());
    }
}

Вывод на моей машине

true
false
person Andreas Dolk    schedule 14.08.2010
comment
Уважаемые downvoters - пожалуйста, оставьте комментарий, если вы считаете, что ответ бесполезен. По крайней мере, комментарий EJP неверен в качестве его ответа ... Вопрос был о SocketChannels, и я все еще уверен, что это объясняет, почему отключение аэропорта не приводит к isConnected() == false. - person Andreas Dolk; 16.08.2010
comment
Я согласен с Андреасом: необъяснимые отрицательные голоса бесполезны или того хуже. Я начинаю рассматривать необъяснимые отрицательные голоса как простой вандализм на сайте. - person user207421; 24.09.2012

isConnected() сообщает вам, вы подключили объект channel, который у вас есть, и не указано, что он возвращает значение false после его закрытия, хотя, по-видимому, это так: см. отвечать. Это не значит, что основное подключение все еще существует. Вы можете сказать это, только используя его: -1 из чтения или исключения говорит вам об этом.

person user207421    schedule 15.08.2010
comment
isConnected() возвращает false на моей машине, когда я закрываю канал на удаленный сервер. Смотрите мой ответ для рабочего примера. - person Andreas Dolk; 15.08.2010
comment
-1 из чтения тоже не работает. Я добавил чтение, и оно заблокировалось (ожидание байтов). Потом я выдернул сетевой кабель, а приложение продолжало блокироваться (в результате нет -1). - person Andreas Dolk; 15.08.2010
comment
Да, -1 от чтения обнаруживает упорядоченное закрытие. Единственный способ обнаружить беспорядочное закрытие с чтением и отсутствием записи — через тайм-аут чтения, который выдает исключение. - person user207421; 15.08.2010