Android - сокет закрывается недостаточно быстро

У меня есть клиентское приложение и серверное приложение. Клиентское приложение отправляет пакеты на серверное приложение через java.net.Socket (Protocol = TCP). На Socket.Close() мое серверное приложение мгновенно показывает мне, что соединение было закрыто - и вот как оно должно работать должным образом. Примечание: вся логика потокового tcp находится во вторичной активности, поэтому я использую функцию onBackPressed() для завершения всей потоковой передачи tcp и переключения на основную активность.

Рабочий сценарий:

@Override
public void onBackPressed(){
      m_socket.Close();
      finish();
}

Как объяснено, сокет закрывается, и сервер немедленно уведомляет, что соединение было закрыто.

Неработающий сценарий, так как Socket.close() кажется слишком медленным:

@Override
public void onBackPressed(){
      m_socket.Close();
      m_wifiManager.disconnect();
      finish();
}

Этот сценарий работает правильно только в 20% случаев. В остальные 80% мое серверное приложение уведомляет, что соединение было закрыто с большой задержкой. По моему мнению, это из-за времени, необходимого для закрытия tcp-сокета - поэтому процесс прерывается из-за разрыва соединения Wi-Fi и не может быть правильного закрытия сокета (#). В качестве доказательства моего мнения: этот сценарий работает в 100% случаев, если я отлаживаю его шаг за шагом. Сервер уведомляет немедленно.

Что я уже пробовал и что тоже не работает должным образом:

  • m_wifiManager.disconnect() в onPause()

  • m_wifiManager.disconnect() в onDestroy()

Итак, мои вопросы:

  1. Правильно ли мое мнение (#)? Не хватает ли времени для закрытия сокета?

  2. Как это исправить? Так что закрытие tcp-сокета завершается правильно, как в первом сценарии, а после этого отключается wifi?

1 ответ

Решение

Проблема, вероятно, связана с опцией сокета SO_LINGER:

Укажите время ожидания при задержке. Эта опция отключает / включает немедленный возврат из close() сокета TCP. Включение этой опции с ненулевым целочисленным таймаутом означает, что close() будет блокировать в ожидании передачи и подтверждения всех данных, записанных в одноранговый узел, после чего сокет будет корректно закрыт. По истечении времени ожидания задержка сокет принудительно закрывается с помощью протокола TCP RST. Включение опции с таймаутом, равным нулю, немедленно приводит к принудительному закрытию. Если указанное значение времени ожидания превышает 65 535, оно будет уменьшено до 65 535.

По умолчанию он отключен, ваш close звонок немедленно возвращается, и вы отключаете Wi-Fi, прежде чем розетка была фактически закрыта. Вам нужно вызвать setSoLinger, чтобы исправить это:

m_socket.setSoLinger(true, 1);
Другие вопросы по тегам