2009-06-09 2 views
22

Когда я использую, например, PuTTY и мое соединение теряется (или когда я делаю руководство ipconfig /release на Windows), он отвечает напрямую и уведомляет, что мое соединение было потеряно.Java обнаруживает потерянное соединение

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

Я пробовал использовать метод Socket.isConnected(), но это только навсегда вернет «истину». Как я могу сделать это на Java?

ответ

18

Ну, лучший способ узнать, прерывается ли ваше соединение, - попытаться прочитать/записать из сокета. Если операция не удалась, вы потеряли соединение когда-нибудь.

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

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

Таким образом, вы можете отслеживать время и время простоя.

+0

Неправильно. Если вы установили тайм-аут чтения, и он запускает, вы получаете исключение, то есть операция завершается с ошибкой, но это не обязательно означает потерянное соединение. – EJP

+2

@EJP Это не всегда правильно, но это даст вам хорошее представление о том, что происходит. – jjnguy

+11

Нет, не будет. Вы не можете различать медленный сервер и потерянное соединение с таймаутом чтения. – EJP

7

Почему бы не использовать метод isReachable() класса java.net.InetAddress?

Как это работает реализация JVM конкретные, но:

Типичная реализация использует ICMP эхо-запросы, если привилегия может быть получена, в противном случае он будет пытаться установить соединение TCP на порт 7 (эхо) от хост назначения.

Если вы хотите сохранить соединение открытым постоянно, так что вы можете видеть, когда это не удается можно подключиться к серверу запуска ECHO protocol себя вместо того, чтобы isReachable() сделать это для вас и чтения и записи данных и подождать, пока она не в состоянии ,

+1

Хмм, может быть, я не понял в своем вопросе. То, что иногда случается в моей системе, заключается в том, что мой интернет падает на несколько секунд, и все соединения закрываются. Через секунду все будет хорошо. Я хочу отслеживать это ежедневно, чтобы сообщать, как часто это происходит. – kresjer

+0

Вы можете напрямую подключиться к серверу ECHO и продолжать отправлять и считывать данные; добавили это в ответ. –

+0

Независимо от того, существует ли существующее соединение, не имеет никакого отношения к 'isReachable()' вообще. – EJP

0

Вы можете пинговать машину каждые несколько секунд, и это было бы довольно точно. Будьте осторожны, чтобы вы не DOS.

Другой вариант - запустить небольшой сервер на удаленной машине и поддерживать соединение с ним.

+0

Как вы узнали, когда вы отключились от небольшого сервера? И ** основное ** использование Java в мобильных устройствах Android, где постоянный pinging и keepalives - это плохая идея, потому что они убивают батарею. – user316117

0

Его, вероятно, проще подключиться к yahoo/google или где-то в этом роде.

URL yahoo = new URL("http://www.yahoo.com/"); 
    URLConnection yc = yahoo.openConnection(); 
    int dataLen = yc.getContentLength() ; 

Neil

+0

Не имеет никакого отношения к тому, что существующее соединение все еще открыто. – EJP

+0

Вопрос заключался в том, как написать «программу Java, которая контролирует мое подключение к Интернету», что будет хорошо. Java напрямую не может контролировать, потеряно ли соединение шпатлевки, но скажет, когда возникает общая сетевая проблема. Вы можете вызвать «netstat» из java для мониторинга сетевого подключения из другого процесса. –

+0

Программисты Windows, использующие WinSock, могут зарегистрироваться для события. Это срабатывает даже после отсоединения кабеля. (с задержкой в ​​несколько секунд) [https://stackoverflow.com/questions/44681648/in-android-how-can-i-receive-an-event-when-my-socket-closes-or-disconnects](link) – user316117

1

Вы можете попробовать глядя на гнездо timeout interval. С коротким таймаутом (I считают по умолчанию является «бесконечным таймаутом»), тогда вы можете уловить исключение или что-то, когда хост становится недоступным.

+1

Это не определяет все случаи. Вы должны прочитать или написать что-то в сокете. – tputkonen

10

Несмотря на то, что протокол TCP/IP является «ориентированным на соединение», обычно никакие данные не отправляются через незанятое соединение. Вы можете открыть сокет в течение года без одного бита, переданного по нему IP-стеком. Чтобы заметить, что соединение потеряно, вам необходимо отправить некоторые данные на уровне приложения. (*) Вы можете попробовать это, отключив телефонный кабель от вашего ADSL-модема. Все подключения на вашем ПК должны оставаться на месте, если в приложениях не существует какого-либо механизма keepalive на уровне приложений.

Таким образом, единственный способ заметить потерянное соединение - открыть TCP-соединение с некоторым сервером и прочитать некоторые данные из него. Возможно, самым простым способом может быть подключение к некоторому FTP-серверу и выборка небольшого файла - или списка каталогов - время от времени. Я никогда не видел общий сервер, который действительно предназначался для использования в этом случае, и владельцам FTP-сервера могут не нравиться клиенты, делающие это.

(*) Существует также механизм, называемый TCP KeepAlive, но во многих ОС вы должны активировать его для всех приложений, и это на самом деле не практично использовать, если вы хотите, чтобы заметить потерю связи быстро

1

Хорошо так что я, наконец, получил это работает с

try 
{ 
    Socket s = new Socket("stackoverflow.com",80); 
    DataOutputStream os = new DataOutputStream(s.getOutputStream()); 
    DataInputStream is = new DataInputStream(s.getInputStream()); 
    while (true) 
    { 
     os.writeBytes("GET /index.html HTTP/1.0\n\n"); 
     is.available(); 
     Thread.sleep(1000); 
    } 
} 
catch (IOException e) 
{ 
    System.out.println("connection probably lost"); 
    e.printStackTrace(); 
} 

не так чисто, как я надеялся, но это не работает, если я оставлю вне os.writeBytes().

+17

Это то, что вы определенно не должны использовать. Его можно почти рассматривать как атаку DOS против stackoverflow.com! – tputkonen

+0

Другим способом сделать это было бы размещение простой страницы/скрипта на веб-хосте, который (скорее всего) не пропустил бы такую ​​постоянную нагрузку, особенно если отображаемая страница была небольшой (просто простая «h» будет делать). Это должно обеспечить небольшой стоп-печать, и если вызовы выполняются каждую секунду или около того, сервер, скорее всего, не погрязнет в результате DOS. В теории все равно. – Kingsolmn

+4

Это вздор. Вызов доступен(), как правило, бессмыслен и вызывает его и отбрасывает результат определенно так. Сон буквально пустая трата времени. Эта техника ничего не делает. – EJP

4

Если клиент отсоединяется правильно, read() вернет -1, readLine() возвращает нуль, readXXX() для любого другого X бросает EOFException. Единственным надежным способом обнаружения потерянного TCP-соединения является запись на него. В итоге, таким образом, произойдет сброс соединения IOException, но для буферизации требуется не менее двух записей.

1

Метод isConnected() внутри Socket.java класс немного вводит в заблуждение. Он не говорит вам, подключен ли сокет к удаленному хосту (например, если он не закрыт). Вместо этого он сообщает вам, был ли сокет когда-либо подключен к удаленному хосту. Если сокет смог подключиться к удаленному хосту вообще, этот метод возвращает true, даже после того, как этот сокет был закрыт. Чтобы узнать, открыт ли сокет, вам необходимо проверить, что isConnected() возвращает true, а isClosed() возвращает false. Например:

boolean connected = socket.isConnected() && !socket.isClosed(); 
+0

_Чтобы сказать, открыт ли сокет, необходимо проверить, что isConnected() возвращает true и isClosed() возвращает false_ Это не похоже на true. См. [Https://stackoverflow.com/questions/44685374/why-am-i-sending-an-rst-if-my-socket-is-connected-and-not-closed] (ссылка) – user316117

+0

@ user316117 что вопрос не ясен, но если isClosed является FALSE, а isConnected имеет значение TRUE, это означает, что вам удалось подключиться, и соединение никогда не было закрыто. Если вы считаете, что отключены, а «isClosed()» возвращает FALSE, вы обнаружили ошибку JDK. См. Эту документацию: https://docs.oracle.com/javase/8/docs/api/java/net/Socket.html#isConnected-- – Alboz

+0

@Alboz Это означает, что вам удалось подключиться, а * socket * еще не завершено. Это не имеет никакого отношения к соединению, поскольку вы заявили о себе в своем собственном ответе. Нет ошибки JDK, если вы не закрыли свой собственный сокет, а затем получили 'isClosed() == false'. – EJP

Смежные вопросы