В чем разница между убийством ВРЕМЕНИ-ОЖИДАНИЯ и SO_REUSEADDR - PullRequest
1 голос
/ 26 февраля 2009

Я читал об использовании опции сокета SO_LINGER, чтобы преднамеренно «убить» состояние ожидания времени, установив время задержки на ноль. Затем автор книги говорит, что мы никогда не должны этого делать и, в общем, мы никогда не должны вмешиваться в состояние ожидания времени. Затем он немедленно рекомендует использовать опцию SO_REUSEADDR, чтобы обойти состояние ожидания времени.

Мой вопрос: в чем разница? В обоих случаях вы преждевременно завершаете состояние ожидания времени и рискуете получить дубликаты сегментов. Почему один хороший, а другой плохой?

Ответы [ 3 ]

2 голосов
/ 26 февраля 2009

TIME_WAIT абсолютно нормально. Это происходит после TCP FIN на локальной стороне, за которым следует подтверждение TCP FIN из удаленного местоположения. В TIME_WAIT вы просто ожидаете, что любые локальные пакеты поступят на локальный адрес. Однако, если есть потерянный или ошибочный пакет, TIME_WAIT гарантирует, что TTL или «время жизни» истечет, прежде чем снова использовать адрес.

Если вы используете SO_REUSEADDR, то, по сути, вы говорите, что я предполагаю, что нет случайных пакетов. Что чаще всего встречается в современных, надежных сетях TCP. Хотя это все еще возможно, это вряд ли.

Установка SO_LINGER в ноль заставляет вас инициировать аварийное закрытие, также называемое «закрытием соединения». Здесь вы не уважаете TIME_WAIT и игнорируете возможность использования пакета с ошибками.

Если вы видите FIN_WAIT_1, то это может вызвать проблемы, так как удаленное местоположение не отправило ACK FIN FIN в ответ на ваш FIN. Таким образом, процесс был либо прерван, либо AC FIN TCP потерян из-за сетевого раздела или из-за неправильного маршрута.

Когда вы видите CLOSE_WAIT, у вас есть проблема, здесь вы пропускаете соединения, так как вы не отправляете ACK FIN FIN при получении TCP FIN.

1 голос
/ 01 марта 2009

Я прочитал еще немного, и это мое понимание того, что происходит (надеюсь, правильно):

Когда вы вызываете close для сокета с установленным SO_REUSEADDR (или ваше приложение падает), происходит следующая последовательность:

  1. TCP Отправляет все оставшиеся данные в буфере отправки и FIN
  2. Если был вызван метод close, он немедленно возвращается без указания, были ли успешно доставлены оставшиеся данные.
  3. Если данные были отправлены, одноранговый узел отправляет данные ACK
  4. Пир отправляет ACK FIN и отправляет свой собственный пакет FIN
  5. FIN однорангового узла подтвержден, а ресурсы сокета освобождены.
  6. Сокет не вводит ВРЕМЯ ОЖИДАНИЯ.

Когда вы закрываете сокет с временем SO_LINGER, установленным на ноль:

  1. TCP отбрасывает любые данные в буфере отправки
  2. TCP отправляет одноранговый пакет RST
  3. Ресурс сокета освобожден.
  4. В розетку не входит ВРЕМЯ ОЖИДАНИЯ

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

0 голосов
/ 08 марта 2011

Я использовал SO_REUSEADDR для подстановки подстановки bind () к локальному порту, для которого в какой-то другой программе уже было открыто соединение. Оказывается, это конкретное использование никогда не вызовет проблем, если только два сокета не пытаются одновременно слушать () для одной и той же комбинации addr / port.

...