В чем разница между Убийством с ОЖИДАНИЕМ ВРЕМЕНИ и SO_REUSEADDR
Вопрос
Я читал об использовании опции сокета SO_LINGER для преднамеренного "уничтожения" состояния ожидания, установив время задержки равным нулю.Затем автор книги продолжает говорить, что мы никогда не должны этого делать и вообще, что мы никогда не должны вмешиваться в состояние ожидания.Затем он немедленно рекомендует использовать опцию SO_REUSEADDR, чтобы обойти состояние ожидания по времени.
Мой вопрос в том, в чем разница?В обоих случаях вы преждевременно завершаете состояние ожидания по времени и рискуете получить повторяющиеся сегменты.Почему одно хорошее, а другое плохое?
Решение 2
Я еще немного почитал, и это мое понимание того, что происходит (надеюсь, правильное):
Когда вы вызываете close в сокете, для которого установлен SO_REUSEADDR ( или ваше приложение выходит из строя), происходит следующая последовательность:
- TCP Отправляет все оставшиеся данные в буфере отправки и FIN
- Если было вызвано close, оно возвращается немедленно, не указывая, были ли успешно доставлены какие-либо оставшиеся данные.
- Если данные были отправлены одноранговый узел отправляет подтверждение данных
- Одноранговый узел отправляет подтверждение FIN и отправляет свой собственный пакет FIN
- FIN однорангового узла подтвержден, и ресурсы сокета освобождены.
- Сокет не вводит ВРЕМЯ -ПОДОЖДИТЕ.
Когда вы закрываете сокет со временем SO_LINGER, установленным на ноль:
- TCP отбрасывает все данные в буфере отправки
- TCP отправляет ПЕРВЫЙ пакет одноранговому узлу
- Ресурс сокета освобожден.
- Сокет не вводит ВРЕМЯ -ПОДОЖДИТЕ
Таким образом, помимо того факта, что установка linger на ноль - это халтура и плохой стиль, это также плохие манеры, поскольку это не приводит к чистому отключению соединения.
Другие советы
TIME_WAIT - это абсолютно нормально.Это происходит после TCP FIN на локальной стороне, за которым следует подтверждение TCP FIN из удаленного местоположения.В режиме TIME_WAIT вы просто ждете, когда любые случайные пакеты прибудут на локальный адрес.Однако, если есть потерянный или случайный пакет, то TIME_WAIT гарантирует, что TTL или "время жизни" истекает, прежде чем использовать адрес снова.
Если вы используете SO_REUSEADDR, то вы, по сути, говорите: "Я предполагаю, что случайных пакетов нет".Что становится все более вероятным в современных, надежных сетях TCP.Хотя это все еще возможно, но маловероятно.
Установка значения SO_LINGER равным нулю приводит к инициированию аварийного закрытия, также называемого "прерыванием соединения". Здесь вы не учитываете TIME_WAIT и игнорируете возможность случайного пакета.
Если вы видите FIN_WAIT_1, то это может вызвать проблемы, так как удаленное местоположение не отправило подтверждение TCP FIN в ответ на ваш FIN.Таким образом, процесс был либо остановлен, либо подтверждение TCP FIN было потеряно из-за сетевого раздела или неправильного маршрута.
Когда вы видите CLOSE_WAIT, у вас проблема, здесь происходит утечка соединений, поскольку вы не отправляете подтверждение TCP FIN при задании TCP FIN.
Я использую SO_REUSEADDR для привязки подстановочного знака () к локальному порту, к которому у какой-то другой программы уже было открыто соединение.Оказывается, это конкретное использование никогда не вызовет проблем до тех пор, пока никакие два сокета не попытаются одновременно прослушать () одну и ту же комбинацию addr / port.