- Windows time wait закрыть
- Что это такое
- Зачем нужно состояние TIME- WAIT
- Принудительная отмена состояния TIME-WAIT
- Резюме
- Как закрыть сокет в состоянии TIME_WAIT
- Все порты TCP/IP, которые находятся в состоянии TIME_WAIT, прежде чем не закрыты после 497 дней от загрузки системы в Windows Vista, Windows 7, Windows Server 2008 и Windows Server 2008 R2
- Симптомы
- Проблема 1
- Проблема 2
- Решение
- Сведения об исправлении
- Предварительные условия
- Сведения о реестре
- Необходимость перезагрузки
- Сведения о замене исправлений
- Сведения о файлах
Windows time wait закрыть
В этом разделе рассказывается о том, что такое состояние TIME-WAIT в протоколе TCP, для чего оно служит и почему не следует пытаться обойти его.
Поскольку состояние TIME-WAIT запрятано глубоко в недрах конечного автомата, управляющего работой TCP, многие программисты только подозреваю о его существовании и смутно представляют себе назначение и важность этого с стояния. Писать приложения TCP/IP можно, ничего не зная о состоянии ТIME-WAIT, но необходимо разобраться в странном, на первый взгляд, поведении приложения (указание 23). Это позволит избежать непредвиденных последствий.
Рассмотрим состояние TIME-WAIT и определим, каково его место в работе TCP-соединения. Затем будет рассказано о назначении этого состояния и его важности, а также, почему и каким образом некоторые программисты пытаются обойти это состояние. В конце дано правильное решение этой задачи.
Что это такое
Состояние TIME-WAIT наступает в ходе разрыва соединения. Помните (указание 7), что для разрыва TCP-соединения нужно обычно обменяться четырьмя сегментами, как показано на рис. 3.8.
На рис. 3.8 показано соединение между двумя приложениями, работающими на хостах 1 и 2. Приложение на хосте 1 закрывает свою сторону соединения, при этом TCP посылает сегмент FIN хосту 2. Хост 2 подтверждает FIN сегментом АСК и доставляет FIN приложению в виде признака конца файла EOF (предполагается, что у приложения есть незавершенная операция чтения, — указание 16). Позже приложение на хосте 2 закрывает свою сторону соединения, посылая FIN хосту 1, который отвечает сегментом АСК.
Рис. 3.8. Разрыв соединения
В этот момент хост 2 окончательно закрывает соединение и освобождает ресурсы. С точки зрения хоста 2, соединения больше не существует. Однако хост 1 закрывает соединение, а переходит в состояние TIME-WAIT и остается в нем в течение двух максимальных продолжительностей существования сегмента (2MSL maximum segment lifetime).
Примечание: Максимальное время существования сегмента (MSL) — это максимальное время, в течение которого сегмент может оставаться в сети, прежде чем будет уничтожен. В каждой IР-датаграммеесть поле TTL (time-to-live — время жизни). Это поле уменьшается нa единицу каждым маршрутизатором, через который проходит датаграмма. Когда TTL становится равным нулю, датаграмма уничтожается. Хотя официально TTL измеряется в секундах, в действительности это поле почти всегда интерпретируется маршрутизаторами как счетчик промежуточных узлов. В RFC 1812 [Baker 1995] этот вопрос обсуждается подробнее.
Прождав время 2MSL, хост 1 также закрывает соединение и освобождает ресурсы.
Относительно состояния TIME-WAIT следует помнить следующее:
- обычно в состояние TIME-WAIT переходит только одна сторона — та, что выполняет активное закрытие;
Примечание: Под активным закрытием понимается отправка первого FIN. Считается, что вторая сторона при этом выполняет пассивное закрытие. Возможно также одновременное закрытие, когда обе стороны закрывают соединение примерно в одно время, поэтому посланные ими FIN одновременно находятся в сети. В этом случае активное закрытие выполняют обе стороны, так что обе переходят в состояние TIME- WAIT.
- в RFC 793 [Postel 1981b] MSL определено равным 2 мин. При этом соединение должно оставаться в состоянии TIME-WAIT в течение 4 мин. На практике это обычно не так. Например, в системах, производных от BSD, MSL равно 30 с, так что состояние TIME-WAIT длится всего 1 мин. Можно встретить и другие значения в диапазоне от 30 с до 2 мин;
- если в то время, когда соединение находится в состоянии TIME-WAIT, прибывает новый сегмент, то таймер на 2MSL перезапускается. Это будет рассматриваться ниже.
Зачем нужно состояние TIME- WAIT
Состояние TIME-WAIT служит двум целям:
- не дать соединению пропасть при потере последнего АСК, посланного активной стороной, в результате чего другая сторона повторно посылает FIN;
- дать время исчезнуть «заблудившимся сегментам», принадлежащим этому соединению.
Рассмотрим каждую из этих причин. В момент, когда сторона, выполняющая активное закрытие, готова подтвердить посланный другой стороной FIN, все данные, отправленные другой стороной, уже получены. Однако последний АСК может потеряться. Если это произойдет, то сторона, выполняющая пассивное закрытие, обнаружит тайм-аут и пошлет свой FIN повторно (так как не получила АСК на последний порядковый номер).
А теперь посмотрим, что случится, если активная сторона не перейдет в состояние TIME-WAIT, а просто закроет соединение. Когда прибывает повторно переданный FIN, у TCP уже нет информации о соединении, поэтому он посылает в ответ RST (сброс), что для другой стороны служит признаком ошибки, а не нормального закрытия соединения. Но, так как сторона, пославшая последний АСК, все-таки перешла в состояние TIME-WAIT, информация о соединении еще хранится, так что она может корректно ответить на повторно отправленный FIN.
Этим объясняется и то, почему 2МSL-таймер перезапускается, если в состоянии TIME-WAIT приходит новый сегмент. Если последний АСК потерян, и другая сторона повторно послала FIN, то сторона, находящаяся в состоянии TIME-WAIT, еще раз подтвердит его и перезапустит таймер на случай, если и этот АСК будет потерян.
Второе назначение состояния TIME-WAIT более важно. Поскольку IР-дата-граммы могут теряться или задерживаться в глобальной сети, TCP использует механизм подтверждений для своевременной повторной передачи неподтвержденных сегментов (указание 1). Если датаграмма просто задержалась в пути, но не потеряна, или потерян подтверждающий ее сегмент АСК, то после прибытия исходных данных могут поступить также и повторно переданные. TCP в этом случае определяет, что порядковые номера поступивших данных находятся вне текущего окна приема, и отбрасывает их.
А что случится, если задержавшийся или повторно переданный сегмент придет после закрытия соединения? Обычно это не проблема, так как TCP просто отбросит данные и пошлет RST. Когда RST дойдет до хоста, отправившего задержавшийся сегмент, то также будет отброшен, поскольку у этого хоста больше нет информации о соединении. Однако если между этими двумя хостами установлено новое соединение с такими же номерами портов, что и раньше, то заблудившийся сегмент может быть принят как принадлежащий новому соединению. Если порядковые номера данных в заблудившемся сегменте попадают в текущее окно приема нового соединения, то данные будут приняты, следовательно, новое соединение — скомпрометировано.
Состояние TIME-WAIT предотвращает такую ситуацию, гарантируя, что два прежних сокета (два IP-адреса и соответствующие им номера портов) повторно не используются, пока все сегменты, оставшиеся от старого соединения, не будут уничтожены. Таким образом, вы видите, что состояние TIME-WAIT играет важную роль в обеспечении надежности протокола TCP. Без него TCP не мог бы гарантировать доставку данных по порядку и без искажений (указание 9).
Принудительная отмена состояния TIME-WAIT
К сожалению, иногда можно досрочно выйти из состояния TIM Е-WAIT. Это называется принудительной отменой (TIME-WAIT assassination) и бывает случай но или намеренно.
Сначала посмотрим, как это может произойти случайно. По стандарта RFC 793, если соединение находится в состоянии TIME-WAIT и приходит RST то соединение должно быть немедленно закрыто. Предположим, что имеет единение в состоянии TIME-WAIT и приходит старый сегмент-дубликат, который TCP не принимает (например, потому, что порядковый номер оказался вне окна приема). TCP посылает в ответ АСК, в котором указано, какой порядковый номер он ожидает (следующий за номером сегмента FIN, посланного другой стороной). Но у хоста на другой стороне уже нет информации о соединении, поэтому этот АСК он отвечает сегментом RST. Когда этот RST приходит хосту, у которого соединение находится в состоянии TIME-WAIT, тот немедленно закрывает соединение, — состояние TIME-WAIT принудительно отменено.
Эта ситуация описана в RFC 1337 [Braden 1992b], где также рассматриваются трудности, сопряженные с принудительной отменой состояния TIME-WAIT. Опасность состоит в возможности «воскрешения» старого соединения (то есть появления соединения с теми же двумя сокетами), что может привести к подтверждению старых данных, десинхронизации соединения с входом в бесконечный цикл и к ошибочному завершению нового соединения.
Это легко предотвратить, изменив протокол TCP так, чтобы в состоянии TIME-WAIT было разрешено игнорировать RST Хотя такое изменение, рекомендованное в RFC 1337, официально не одобрено, тем не менее в некоторых стеках оно реализовано.
Принудительно отменить состояние TIME-WAIT можно и намеренно. С помощью опции сокета SO_LINGER программист требует немедленного закрытия соединения даже в том случае, когда приложение выполняет «активное закрытие. Этот сомнительный прием иногда рекомендуют применять, чтобы вывести «упавший» сервер из состояния TIME-WAIT и запустить его заново. Подробнее об этой проблеме и более правильном способе ее решения будет рассказано в указании 23. Корректно написанное приложение никогда не должно манипулировать состоянием TIME-WAIT, поскольку это неотъемлемая часть механизма обеспечения надежности TCP.
Обычно, когда приложение закрывает соединение, вызов close или closesocket возвращается немедленно, даже если в буфере передачи еще есть данные. Разумеется, TCP будет пытаться доставить эти данные, но приложение не имеет информации, удалось ли это. Чтобы решить эту проблему, можно установить опцию сокета SO_LINGER. Для этого следует заполнить структуру linger и вызывать setsockopt с параметром SO_LINGER.
В большинстве UNIX-систем структура linger определена в заголовочном файле /usr/include/sys/socket.h. В системе Windows она находится в файле winsock2.h. В любом случае она выглядит так:
int l_onoff; /*Включить/выключить опцию.*/
int l_linger; /*Время задержки.*/
Если поле l_onoff равно нулю, то опция задержки отключается, и выбирает поведение по умолчанию — вызов close или closesocket возвращается немедленно, а ядро продолжает попытки доставить еще не переданные данные. Если же l_onoff не равно нулю, то работа зависит от значения поля l_linger. Если l_linger отлично от нуля, то считается, что это время, в течение которого ядро должно подождать отправки и подтверждения оставшихся в буфере передает, данных. При этом close или closesocket не возвращается, пока данные не будут доставлены или не истечет указанное время.
Если к моменту завершения ожидания данные еще не доставлены, то close или closesocket возвращает код EWOULDBLOCK, и недоставленные данные могут быть потеряны. Если все данные уже доставлены, то оба вызова возвращают нуль.
Примечание: К сожалению, семантика поля l_linger зависит от реализации. В Windows и некоторых реализациях UNIX это число секунд, на которое следует задержать закрытие сокета. В системах, производных от BSD, это число тактов таймера (хотя в документации сказано, что это число секунд).
Используя опцию SO_LINGER таким способом, вы гарантируете, что данные будут доставлены уровню TCP на удаленном хосте. Но они не обязательно будут прочитаны приложением. Более правильный способ добиться последнего — использовать процедуру аккуратного размыкания, описанную в указании 16.
Если поле l_linger равно нулю, то соединение разрывается. Это означает, что хосту на другом конце посылается RST, и соединение закрывается немедленно, не переходя в состояние TIME-WAIT. Это преднамеренная принудительная отмена состояния TIME-WAIT, о которой упоминалось выше. Как было сказано, это опасный прием, который в обычном приложении применять не следует.
Резюме
В этом разделе обсуждено состояние TIME-WAIT, которое часто понимают неправильно. Это состояние — важная часть механизма обеспечения надежности протокола TCP, и попытки обойти его неверны. Преждевременный выход из состояния TIME-WAIT может быть обусловлен «естественным» стечением обстоятельств в сети или программой, которая манипулирует опцией SO_LINGER.
Как закрыть сокет в состоянии TIME_WAIT
Иногда возникает необходимость прибить какое-то TCP-соединение. Часто для решения этой задачи с помощью lsof или netstat вычисляют процесс, который это соединение обслуживает и что-то с этим процессом делают (например, kill -9). Но вот для ситуации когда процесс найти не получается (например, он завершился аварийно и не закрыл после себя соединение) или прибивать процесс нельзя, уже задачка становиться не совсем тривиальной.
Состояния TCP-соединения и переходы между ними
Тут может пригодится perl-утилитка под названием killcx, которая должна помочь и в случае когда TCP-соединение пребывает в состоянии TIME_WAIT. Работает примерно так:
В качестве аргумента ей нужно передать IP-адрес и порт удаленной стороны TCP-соединения. В этом примере я подключился по SSH с клиента 10.11.12.13 на сервер с адресом 10.10.10.10. Команда выполнялась на сервере 10.10.10.10.
Для работы утилита требует наличия следующих perl-модулей:
* Net::RawIP (для создания spoofed packets, CPAN-ом он у меня просто так ставиться не захотел, жалуясь на тесты, пришлось сделать force install Net::RawIP)
* Net::Pcap (для перехвата TCP-пакетов).
* NetPacket::Ethernet (для декодирования TCP/IP-пакетов).
Также может потребоваться предварительная установка пакета libpcap-devel.
Также с похожей функциональностью есть утилита cutter. Но она работает только в случае, если запускается на промежуточном между клиентом и сервером роутере.
Попытка оборвать соединения с сервисом, запущенном на порту 62616 сервера 10.10.10.10, с клиента 10.20.20.20:
Что, в принципе, было ожидаемо. На роутере я ее пока запускать не пробовал.
Ещё есть третий вариант принудительного завершения TCP-соединения — использование утилиты tcpkill. Её преимущество в том, что ее намного проще установить (по сравнению с killcx) – достаточно просто установить пакет dsniff, в состав которого она входит. Какое именно соединение обрывать ей нужно указать с помощью BPF-выражения, формат которых знаком каждому, кто пользовался tcpdump-ом.
Здесь я подключился по SSH с хоста 192.168.1.51 на сервер 192.168.1.1 и запустил сначала команду lsof чтобы узнать порт на стороне клиента (34749). Затем передал его в качестве аргумента tcpkill-у и соединение сразу было разорвано. Следует учитывать, что tcpkill сработает только для соединения, по которому передаются хоть какие-то данные. В противном случае он просто будет висеть в ожидании следующей порции трафика.
Еще один, пожалуй, самый изящный вариант с использованием отладчика gdb. Опять поключаемся по SSH с 192.168.1.51 на 192.168.1.1 и что-то там запускаем для красоты, например такой цикл:
Все порты TCP/IP, которые находятся в состоянии TIME_WAIT, прежде чем не закрыты после 497 дней от загрузки системы в Windows Vista, Windows 7, Windows Server 2008 и Windows Server 2008 R2
Симптомы
На компьютере под управлением Windows Vista, Windows 7, Windows Server 2008 или Windows Server 2008 R2 возникают следующие проблемы.
Проблема 1
Все порты TCP/IP, которые находятся в состоянии TIME_WAIT, прежде чем не закрыты после 497 дней от загрузки системы. Таким образом порты TCP/IP может быть исчерпан, и не могут быть созданы новые сеансы TCP/IP.
Примечание. Некоторые сетевые операции на этом компьютере может быть подвержена этой проблеме. Например при попытке использовать некоторые средства удаленного администрирования для управления контроллером домена под управлением Windows Server 2008, работает более 497 дней. В этом примере средства удаленного администрирования не может подключиться к контроллеру домена.
Проблема 2
Разгрузка TCP/IP chimney сбой после 248.5 дней. Таким образом систем перестанет отвечать на запросы после используются 248.5 дней, если Разгрузка подключений.
Решение
Сведения об исправлении
Существует исправление от корпорации Майкрософт. Однако данное исправление предназначено для устранения только проблемы, описанной в этой статье. Применяйте это исправление только в тех случаях, когда наблюдается проблема, описанная в данной статье. Это исправление может проходить дополнительное тестирование. Таким образом если вы не подвержены серьезно этой проблеме, рекомендуется дождаться следующего пакета обновления, содержащего это исправление.
Если исправление доступно для скачивания, имеется раздел «Пакет исправлений доступен для скачивания» в верхней части этой статьи базы знаний. Если этот раздел не отображается, обратитесь в службу поддержки для получения исправления.
Примечание. Если наблюдаются другие проблемы или необходимо устранить неполадки, вам может понадобиться создать отдельный запрос на обслуживание. Стандартная оплата за поддержку будет взиматься только за дополнительные вопросы и проблемы, которые не соответствуют требованиям конкретного исправления. Для получения полного списка телефонов поддержки и обслуживания клиентов корпорации Майкрософт, или для создания отдельного запроса на обслуживание, посетите следующий веб-сайт Майкрософт:
Примечание. В форме «Пакет исправлений доступен для скачивания» отображаются языки, для которых доступно исправление. Если нужный язык не отображается, значит исправление для данного языка отсутствует.
Предварительные условия
Чтобы применить это исправление, необходимо использовать одну из следующих операционных систем:
Пакет обновления 1 (SP1) для Windows Vista
Windows Vista с пакетом обновления 2 (SP2)
Windows Server 2008
Windows Server 2008 с пакетом обновления 2 (SP2)
Windows 7 с пакетом обновления 1 (SP1)
Windows Server 2008 R2
Windows Server 2008 R2 с пакетом обновления 1 (SP1)
Чтобы получить дополнительные сведения о получении пакета обновления для Windows Vista, щелкните следующий номер статьи базы знаний Майкрософт:
как получить последний пакет обновления для Windows Vista
Дополнительные сведения о том, как получить пакет обновления для Windows Server 2008, щелкните следующий номер статьи базы знаний Майкрософт:
Как получить последний пакет обновления для Windows Server 2008
Дополнительные сведения о получении пакета обновления Windows Server 2008 R2 или Windows 7 щелкните следующий номер статьи базы знаний Майкрософт:
сведения о Пакет обновления 1 для Windows 7 и Windows Server 2008 R2
Сведения о реестре
Для использования исправления из этого пакета нет необходимости вносить изменения в реестр.
Необходимость перезагрузки
После установки исправления компьютер необходимо перезагрузить.
Сведения о замене исправлений
Это исправление не заменяет ранее выпущенные исправления.
Сведения о файлах
Глобальная версия этого исправления устанавливает файлы с атрибутами, указанными в приведенных ниже таблицах. Дата и время для файлов указаны в формате UTC. Дата и время для файлов на локальном компьютере отображаются в местном времени с вашим текущим смещением летнего времени (DST). Кроме того, при выполнении определенных операций с файлами, даты и время могут изменяться.
Примечания к сведениям о файле Windows Vista и Windows Server 2008
Важно. Исправления для Windows Server 2008 и Windows Vista исправления включены в те же пакеты. Однако только «Windows Vista» отображается на странице запрос исправления. Для получения пакета исправлений, который применяется к одной или обеих операционных систем, установите исправления, перечисленные в разделе «Windows Vista» на странице. Всегда смотрите раздел «Информация в данной статье относится к следующим продуктам» статьи для определения фактических операционных систем, к которым применяется каждое исправление.
Файлы, относящиеся к определенному продукту, этапу разработки (RTM, SP n) и направлению поддержки (LDR, GDR) можно определить путем проверки номера версий файлов, как показано в следующей таблице.
1 Пакет обновления интегрируется в окончательной версии Windows Server 2008. Таким образом файлов выпуска RTM относятся только к системе Windows Vista. Файлов выпуска RTM выглядят следующим образом: 6.0.0000. номер версии XXXXXX .
Файлы MANIFEST (.manifest) и MUM (.mum), устанавливаемые для каждой среды, указаны отдельно в разделе «Сведения о дополнительных файлах для системы Windows Vista и Windows Server 2008». MUM файлы и файлы МАНИФЕСТА и связанные файлы каталога безопасности (.cat), очень важны для поддержания состояния обновляемого компонента. Файлы каталога безопасности, для которых не перечислены атрибуты, подписаны цифровой подписью корпорации Майкрософт.