2015-08-12 2 views
1

Проблема:Sockets прекратить отправку сообщений, но не таймаут

Я делаю приложение, которое имеет мгновенный обмен сообщениями. По большей части сообщения отправляются и принимаются без каких-либо проблем. Но через некоторое время, где-то между 10 и 40 минутами, сообщения больше не доходят до сервера, если сокет клиента не использовался некоторое время. Например, если я общаюсь с кем-то, оставлю приложение открытым, вздремнуть и снова вернуться в чат, тогда сообщения не будут отправляться. Я на 99% уверен, что это не проблема на стороне сервера, потому что я распечатываю все, что он получает (и он ничего не получает), и он отлично работает, если я вхожу в систему с другим телефоном.

Что я пробовал:

Сначала я думал, что это был вопрос времени ожидания на стороне клиента, так как на стороне сервера, я продолжал получать говоря об ошибке, «сброс соединения по равному», где-то в что инвервал 10-40 минут. Я (почти) решить это с помощью Java.net.socket «s connect() метода со значением таймаута 0, что дает бесконечное время ожидания:

clientSocket = new Socket(); 
clientSocket.connect(new InetSocketAddress(ServerInfo.IP, ServerInfo.PORT_NUMBER), 0); 

Я редко получаю„сброс соединения пэра“сообщение об ошибке теперь, но загадочная проблема сообщений, которые не отправляются через некоторое время, остается.

Код:

Это моя sendMessage функция, которая всегда регистрирует "SOCKET ОПЕРАТОРА ОТПРАВКИ СООБЩЕНИЕ:" сообщение":

public boolean sendMessage(String message) 
{              
     PrintWriter out = null; 

     try 
     { 
      out = new PrintWriter(clientSocket.getOutputStream(), true); 
      Log.i("MY_TAG", "SOCKET OPERATOR SENDING MESSAGE: " + message); 

     } 
     catch (IOException e) 
     { 
      e.printStackTrace(); 
      Log.i("MY_TAG", "SOCKET OPERATOR FAILEDD TO SEND MESSAGE WITH EXCEPTION: " + e.getMessage()); 

      return false;     
     } 


     out.println(message); 

     return true;    
} 

Вопрос:

Что на земле может возможно, это проблема или как я могу ее отладить?

ответ

3

Регистрация в точке, которую вы делаете, бесполезна. Пока ничего не произошло.

Если соединение не работает, рано или поздно отправка вызовет IOException: connection reset. Но не в первый раз из-за буферизации сокета.

И когда вы получите это исключение, не просто возвращайте false. Закройте соединение.

HOWEVER проблема здесь PrintWriter. Это проглатывает исключения. См. Javadoc. Либо вызовите checkError(), который возвращает логическое значение, указывающее, было ли исключение, или, что еще лучше, не использовать PrintWriter: используйте BufferedWriter.write() и .newLine() и .flush(), все из которых могут выбрасывать IOExceptions. Это лучше, потому что вы можете видеть, что на самом деле было исключением. Вам, конечно, придется переместить все это в блок try, опередив в настоящее время вводящее в заблуждение сообщение журнала.

И не используйте новый PrintWriter или BufferedWriter за сообщение. Используйте тот же самый для жизни сокета.

+0

Ничего себе, я не понимал, что проблема заключается именно в том, что PrintWriter скрывает исключения ввода-вывода. Я думаю, что это, скорее всего, проблема. (Хотя я не желаю удалять функцию сердечного ритма и ждать полчаса, чтобы проверить). Спасибо. Я обязательно буду следовать всем вашим советам. – Kacy

+0

О, но что вы подозреваете, вызвало падение связи в первую очередь? Я установил бесконечный тайм-аут на стороне клиента. Было ли это серверной стороной, хотя на полчаса продолжалось работать? – Kacy

+0

Не знаю, извините, может быть тайм-аут отображения NAT, как вы предполагали. – EJP

1

Перед отправкой любого сообщения вы должны проверить, существует ли соединение b/w-клиента и сервера.

Есть вероятность, что если сетевое соединение будет медленным или будет отключено, соединение сломается или иногда оно станет мертвым соединением со стороны сервера, потому что не было связи b/w обоих.

вы можете попробовать две вещи:

1. Сделать общий метод, который на посылающего сообщение проверяет если: соединение существует, то просто отправить сообщение еще: сначала сделать подключение и отправить это сообщение ,

Мы столкнулись с той же проблемой в Websockets и использовали тот же самый startegy.

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

Для нас первая стратегия разработана и лучше.

Дайте ему попробовать.:)

+0

Я понял, что сердцебиение будет работать, но хотелось понять проблему, прежде чем я ее осуществил. Спасибо за предложения. Вы меня поймали в правильном направлении, и я думаю, что проблема не вызвана клиентским устройством или сервером, а скорее тем, что находится между ними. В одном из ответов на этот пост упоминается, что: http://stackoverflow.com/questions/865987/do-i-need-to-heartbeat-to-keep-a-tcp-connection-open Он упоминает брандмауэр, но Я думаю, что это может быть мой NAT-маршрутизатор с собственным механизмом тайм-аута. – Kacy

+0

вы можете использовать метод readyState() сокета, чтобы проверить, установлено или отключено соединение (мертво). –

+1

Ни один из этих методов не существует в документации '' Java.net.socket'. Самое близкое к тому, что вы описываете, это метод isConnected(), но который всегда возвращает true после подключения сокета независимо от того, были потеряны. – Kacy

0

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

Мое решение заключается в использовании функции сердечного ритма (наряду с изменением моего использования PrintWriter, как предложено EJP), отправляя от клиента на сервер каждые 45 секунд. Скорее всего, я буду рандомизировать время, чтобы просто обработать случай, когда тонна людей регистрируется в одно и то же время и влияет на производительность сервера.

+1

Там нет «не об этом». Для отправки требуется подтверждение и, если оно не поступило, повторите попытку, и если все это не удастся, соединение в конечном итоге будет сброшено отправителем. – EJP

+0

@EJP Соединение не сбрасывается только потому, что один пакет не приводит к тому, что клиент получает ACK обратно с сервера. Это означает, что каждый раз, когда ACK теряется/удаляется в сети, независимо от рабочего соединения, эти соединения будут сброшены. И это неправда. Однако верно, что переводы выполняются в NAT-маршрутизаторах. – Kacy

+0

Если пакет не смог получить подтверждение * после соответствующего количества попыток и тайм-аутов *, соединение действительно будет сброшено. Я ничего не говорил о том, что потерянные ACK потеряны, или трансляции NAT, а не тайм-аут. Не вставляйте слова в рот. – EJP

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