понедельник, 11 июня 2012 г.

Вспомним молодость/Вспоминаем TCP

Мое изложение главы 18 из книги "TCP/IP КРУПНЫМ ПЛАНОМ".

Я хочу рассказать вам шутку про tcp 
и буду ее рассказывать, пока до вас не дойдет.


Установка соединения:
Клиент создает соединение и посылает серверу SYN_SENT, сервер, находящийся в состоянии LISTEN, отвечает SYN_RCVD (SYN, ACK). Клиент переходит в ESTABLISHED и отправляет серверу ACK, в знак того, что понял, что сервер готов установить соединение. Сервер получил этот ACK и перешел в ESTABLISHED.

Разрыв соединения:
Клиент переходит в FIN_WAIT1 и шлет FIN . Сервер получает FIN, переходит в CLOSE_WAIT, и из состояния CLOSE_WAIT отправляет подтверждение ACK. Сервер получает этот ACK, переходит в FIN_WAIT2, и ждет закрытия потока со стороны сервера. Когда сервер посылает свой FIN, клиент находится в состоянии TIME_WAIT. По истечении некоторого времени, находясь с состоянии TIME_WAIT, клиент отправляет ACK серверу и сервер тоже закрывает свое соединение.
TIME_WAIT нужно для того, чтобы во-первых клиент успел получить последний ACK от сервера, и во-вторых, в течении этого времени пара сокетов (сокет клиента и сокет сервера) не могут быть повторно использованы, чтобы задержавшиеся сегменты от законченного соединения не принялись в новом соединении(концепция тихого времени - quiet time).
Чему равер TIME_WAIT? TIME_WAIT равен 2MSL. MSL может быть 30 сек, 1 мин или 2 мин, в зависимости от системы. В случает, если MSL равен 30 сек, то TIME_WAIT будет 1 минуту. Т.е. после окончания 1 минуты, TCP сможет создать соединение на сокете, который находился в состоянии TIME_WAIT. 
Если клиент пытается установить соединение на несуществующий порт на сервере, то сервер отправляет пакет с битом RST(RESET) - сброс.
Если клиент оптправляет RESET серверу, то соединение закрывается немедленно, не отправляются FIN сегменты и не тратится время на ожидание подтверждения ACK. Со стороны сервера это выглядит как "Connection reset by peer".
Если на стороне клиента в процессе tcp сессии сдохла сетевушка или отключилось питание, то tcp клиента не успел послать FIN. На стороне сервера при этом tcp сессия все еще открыта. После того, как клиентский компьютер включится и попытается отправить данные на сервер, сервер отправляет серверу RESET и закрывает свою сессию.

Одновременное открытие:
Если оба хоста заранее знают порты, на котором оба установят соединения и попытаются инициализировать соединение одновременно, то это будет одновременным открытием (но не динамически назначаемые порты). Для установки такого соединения требуется уже 4 сегмента.
Одновременное закрытие:
Тут все просто. Оба хоста из ESTABLISHED переходят в FIN_WAIT1 и отправляют FIN

Немного про флаги: 
PSH (PUSH) - отправитель этого флага говорит получателю (этого флага) передать все имеющиеся данные (у этого получателя) процессу, которому данные предназначены. Этот флаг  устанавливает сам TCP.
URG (URGENT) - флаг срочности, позволяет отправителю флага сообщить получателю флага, что в поток были помещены срочные данные. Что делать со срочными данными, должен решить получатель. При этом сообщается последний бит срочных данных, но нет возможности узнать, где эти срочные данные начались. (Указатель срочности используется, например, когда пользователь прерывает передачу файла по FTP).
Алгоритм Нагла:
В tcp соединении может присутствовать только один неподтвержденный маленький сегмент. Пока ACK на этот сегмент не придет, остальные маленькие сегменты склеиваются, чтобы быть отправленными вместе(единым сегментом), когда подтверждение таки дойдет. Т.о. мы не засаряем сеть мелкими сегментами.
Дублирование потерянных(битых) пакетов:

Я тут своими словами: 
Сервер отправил 1-43 пакет, которые клиент успешно принял и отправил на них ACK. Затем сервер отправляет 45 пакет, который клиент не получил(или получил с неверное контрольной суммой), тут же сервер отправил еще 8 пакетов, которые уместились в win(window size) клиента.
Так вот, клиент не получил 45 сегмент, но не молчит, а сообщает серверу: ACK с номером последовательности  каждый раз, когда сервер присылал ему след. сегмент, но не 45-ый. После третьего дублированного ACK сервер понимает, что 45 сегмент надо продублировать, и посылает его клиенту повторно. После того, как клиент получает 45 сегмент, он не подтверждает его прием, а просто одним сегментом подтверждает прием следующих после 45-го восьми сегментов, что уместились в его окне. Т.о. сервер понимает, что клиент получил и 45 и 8 после него сегменты. 

Синдром "глупого окна"
В общем случае это обмен между хостами небольшими сегментами, вместо полноразмерных сегментов. Может происходить из-за объявления слишком маленького окна(win) получателем или если со стороны отправителя, например, выключен алгоритм Нагла.

Таймер keepalive:
Бывают случаи, когда сервер или клиент в принципе закончили обмен данными и пока соединение установлено, но пакеты по нему не ходят, и тут клиент выключается. Сервер при этом не подозревает, что клиент отключился(умер, сдох роутер между ними), и так и держит соединение в ESTABLISHED. Таймер keepalive задает время, через которое сервер будет проверять жив ли клиент. Если на первый запрос клиент промолчал, через 75 сек сервер еще раз спрашивает. Через 10 попыток сервер считает клиента умершим и закрывает соединение. 

Тут же по теме: 
Win (window size) - максимальный размер данных, которые приложение готово принять(имеется ввиду не один сегмент, а максимальный объем данных, которые tcp может помнить в промежутке между: "принял от отправителя" до "передал приложению, которому предназначаются данные").
MSS - максимальный размер сегмента, который может быть принят отправителем(Я сообщаю тебе, что могу принять не больше чем 1024 байта данных(именно данных, без заголовков)). Максимум - 65535 байт.
MTU - максимальный размер блока передачи. Характеристика канального уровня, определяется сетевым интерфейсом. Ограничивает максимальный размер ip пакета(датаграммы).

Ну и пара слов про LFP :). 
Отталкивая от формулы: Емкость канала (в битах ) = ширине полосы (бит/сек) * rtt.
RTT (время возврата)- время необходимое, чтобы сегмент дошел до получателя + отправителем был получен ответ на этот сегмент.
Ту так вот, каналы с большой емкостью называются каналами с повышенной пропускной способностью. Получить такой канал можно или увеличивая ширину полосы или увеличивая время возврата, ну или увеличивая оба параметра. Некоторые проблемы с такими каналами:
1 - window size ограничен 16 битным числом, т.е.  65535 байтами. Для увеличения окна в tcp используется масштабирование окна. Задается режим - 0 или 1 - вкл или выкл и задается сдвиг, для добавления битности числу(mss).
2 - номер последовательности. Ух, сами читайте все формулы, я скажу просто :). Если потеряется сегмент 334575,в условиях оч широкого канала есть вероятность, что номера последовательности 2 в 32 степени кончатся и начнутся с начала раньше чем пройдут таймауты ip и tcp. Т.е. совершенно новый сегмент с номером 334575 будет принят за тот потерянный до того, как тот потерянный сегмент сервер сможет повторно послать. Как избежать? Заполняем поле временных марок!

Пока устала, может позже допишу.. 


Инфа в тему: TCP Extensions for Long-Delay Paths

Комментариев нет: