Timeoutlnterval = EstimatedRTT + 4 х DevRTT.

4. Надежная передача данных

Протокол сетевого уровня IP предоставляет транспортному уровню службу ненадежной передачи данных. IP не дает гарантий относительно доставки дейтаграмм, сохранения порядка их следования и корректности информации. При перегрузке маршрутизаторов дейтаграммы могут быть потеряны, порядок их получения может отличаться от порядка отправки, и, кроме того, допускаются искажения битов (изменения значений с 0 на 1 и наоборот). Поскольку дейтаграммы являются средством передачи сегментов транспортного уровня, последний сталкивается с перечисленными проблемами.

Тем не менее протокол TCP способен обеспечить надежную передачу данных, используя службы ненадежной передачи протокола IP. TCP гарантирует, что данные, которые процесс считывает из своего TCP-буфера, не содержат искажений, пропусков и дублирований, а также расположены в правильном порядке. Другими словами, входной поток принимающей стороны в точности совпадает с выходным потоком передающей стороны. Ниже мы увидим, каким образом TCP обеспечивает подобные гарантии. Оказывается, в основе его функционирования лежат многие из принципов, описанных в предыдущем разделе этой главы.

Простым и удобным механизмом, которым мы пользовались при построении собственного протокола надежной передачи данных, является связывание каждого переданного неподтвержденного сегмента с индивидуальным таймером. На практике управление таймерами оказывается далеко не столь тривиальным, и в RFC 2988 рекомендуется использовать единственный таймер для всех сегментов, которые должны быть квитированы. Эта рекомендация учитывается и в протоколе TCP.

НЕ нашли? Не то? Что вы ищете?

Изучение механизма надежной передачи данных в TCP будет происходить в два этапа. Сначала мы рассмотрим упрощенную модель передающей стороны TCP, в которой интервалы ожидания являются единственным средством обнаружения потерь пакетов. Затем мы усложним модель, введя в нее механизм дублирования подтверждений. При этом мы будем опираться на предположение о том, что передача данных ведется в одном направлении, от хоста А к хосту В, и объем передаваемых данных значителен (например, хост А посылает файл большого размера).

Упрощенная программа на псевдоязыке для передающей стороны приведена ниже. В ней обрабатываются три события, связанные с передачей данных: получение новых данных от верхнего уровня, истечение интервала ожидания и получение подтверждения (АСК). При наступлении первого из событий данные заключаются в сегмент, который затем передается протоколу IP. Каждый сегмент содержит порядковый номер, равный номеру первого байта данных в нем. Кроме того, если таймер не был запущен ранее для какого-либо сегмента, в момент передачи текущего сегмента протоколу IP происходит его запуск (представьте себе, что таймер связан с самым «старым» неподтвержденным сегментом). Интервал ожидания Timeoutlnterval, устанавливаемый для таймера, вычисляется по формуле, приведенной выше.

NextSeqNum = InitialSeqNumber

SendBase = InitialSeqNumber

Цикл (бесконечно) {

switch(co6biTne)

событие: получены данные от верхнего уровня

создать TCP-сегмент с порядковым номером

NextSeqNum if (таймер не запущен)

запустить таймер

передать сегмент протоколу IP

NextSeqNum = NextSeqNum + length(данные)

break;

событие: истек интервал ожидания

снова послать неподтвержденный сегмент с наименьшим порядковым номером

запустить таймер

break;

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

if (у > SendBase) {

Sendbase = у

if (есть хотя бы 1 неподтвержденный сегмент)

запустить таймер

}

break;

} /* конец тела бесконечного цикла*/

При наступлении второго события (истечения интервала ожидания) TCP производит повторную передачу сегмента, для которого истек интервал ожидания, а затем перезапускает таймер.

Наконец, последним событием, на которое реагирует протокол TCP, является получение квитанции (то есть сегмента, содержащего корректное значение в поле подтверждения). TCP сравнивает значение поля подтверждения с переменной SendBase, хранящей значение порядкового номера самого старого из неподтвержденных байтов (значение SendBase – 1, таким образом, является порядковым номером последнего байта, принятого принимающей стороной без ошибок и в правильном порядке). Как упоминалось ранее, в протоколе TCP используются общие квитанции, то есть квитанция с номером подтверждения у свидетельствует о том, что все байты с номерами, меньшими у, успешно приняты. Если оказывается, что у > SendBase, это означает, что пришедшая квитанция подтверждает получение одного или нескольких сегментов, не квитированных ранее; значение SendBase обновляется, и для этих сегментов происходиг перезапуск таймера.

В протоколе TCP используется механизм конвейеризации, то есть передаются несколько сегментов без ожидания квитанции для каждого из них. Мы убедились в том, что конвейеризация может значительно повысить коэффициент полезности, если отношение времени передачи одного сегмента ко времени оборота мало. Число сегментов, которые могут быть переданы без ожидания квитанций, определяется механизмами контроля потоков данных и перегрузки.

Несколько интересных сценариев

Итак, мы упрощенно олисали механизм, с помощью которого TCP осуществляет надежную передачу данных. Тем не менее оказывается, что даже такая простая модель не лишена некоторых нюансов. Сейчас мы рассмотрим несколько ситуаций и соответствующих режимов работы протокола TCP. Первую ситуацию иллюстрирует рис. 8.6, где хост А посылает один сегмент хосту В. Предположим, что сегмент имеет порядковый номер 92 и содержит 8 байт данных. После передачи этого сегмента хост А ожидает от хоста В сегмент с номером подтверждения 100. Положим, что сегмент, посланный хостом А, успешно получен, а сегмент хоста В оказывается потерянным. В этом случае происходит истечение интервала ожидания, и хост А отправляет свой сегмент повторно. Хост В получает этот сегмент и по его порядковому номеру выясняет, что такой сегмент им уже принят. Это приводит к удалению повторно переданного сегмента.

Рис. 8.6. Повторная передача, вызванная потерей квитанции

Вторая ситуация представлена на рис. 8.7. Хост А передает подряд два сегмента, первый из которых имеет порядковый номер 92 и содержит 8 байт данных, а второй сегмент имеет порядковый номер 100 и содержит 20 байт данных. Предположим, что оба сегмента успешно принимаются хостом В, который генерирует две квитанции с номерами подтверждения 100 и 120 соответственно. Пусть ни одна из квитанций не достигает хоста А до истечения интервала ожидания. В этом случае хост А повторно пересылает сегмент с номером 92 и перезапускает таймер. Поскольку хост А получает квитанцию для второго сегмента до нового истечения интервала ожидания, повторной передачи второго сегмента не происходит.

Рис. 8.7 Повторная передача сегмента с номером 100 не производится

Третья ситуация приведена на рис. 8.8 и отличается от второй тем, что квитанция для первого из сегментов теряется, а вторая квитанция (с номером подтверждения 120) достигает хоста А до истечения интервала ожидания. Получение этой квитанции хостом А сигнализирует о том, что все байты до 119 включительно успешно получены хостом В; таким образом, хосту А не требуется повторно пересылать ни один из двух сегментов.

Рис. 8.8 Общая квитанция позволяет избежать повторной передачи первого сегмента

Удвоение интервала ожидания

Здесь мы рассмотрим несколько модификаций предыдущей модели, присутствующих в большинстве реализаций протокола TCP. Первая модификация заключается в изменении длительности интервала ожидания по его истечении. Мы знаем, что по истечении интервала ожидания TCP осуществляет повторную передачу неподтвержденного сегмента с наименьшим порядковым номером. При этом оказывается, что вместо расчета нового интервала ожидания с использованием значений EstimatedRTT и DevRTT (см. «Время оборота и интервал ожидания» данного раздела) TCP удваивает текущее значение интервала ожидания. Пусть, например, при первом переполнении таймера было установлено время ожидания 0,75 с. Первая повторная передача сегмента будет происходить с таймером, установленным на 1,5 с. Если интервал ожидания вновь истечет, таймер будет установлен на 3 с, и т. д. Таким образом, увеличение интервала ожидания происходит экспоненциально при каждой новой повторной передаче. Однако, если запуск таймера происходит при наступлении одного из двух других событий (получения данных от верхнего уровня или квитанции), длительность интервала ожидания рассчитывается обычным способом — при помощи величин EstimatedRTT и DevRTT.

Такая модификация является «мягкой» формой контролирования перегрузки (другие механизмы контроля перегрузки будут рассмотрены в разделе «Контроль перегрузок в ТСР»). Истечение интервала ожидания, как правило, свидетельствует о наличии перегрузок в сети, то есть скоплении большого числа пакетов на одном или нескольких маршрутизаторах, что приводит к значительным задержкам и потерям данных. Если при этом стороны продолжают непрерывно передавать пакеты, перегрузка может стать еще более значительной. Увеличение интервалов ожидания приводит к тому, что повторные передачи осуществляются через возрастающие промежутки времени. Подобный механизм используется в технологии Ethernet.

Ускоренная повторная передача

Одним из недостатков механизма повторной передачи с интервалами ожидания является то, что интервалы ожидания часто оказываются относительно долгими. При потере пакета передающая сторона вынуждена ждать истечения интервала ожидания для того, чтобы осуществить повторную передачу, тем самым увеличивая общую задержку. Здесь на помощь приходит механизм дублирования подтверждений, позволяющий передающей стороне обнаруживать потери пакетов до истечения интервала ожидания. Дублирующее подтверждение — это копия положительной квитанции предыдущего сегмента, отправляемая в ответ на получение следующего сегмента, если порядковый номер последнего превышает ожидаемый. Чтобы понять реакцию передающей стороны на появление дублирующих подтверждений, сначала необходимо выяснить причину, побуждающую к использованию такого механизма. В табл. 8.1 приведены основные правила генерации квитанций принимающей стороной TCP. При получении сегмента, порядковый номер которого превышает ожидаемый, протокол регистрирует наличие недостающего сегмента. Появление недостающих сегментов может быть обусловлено потерей сегментов или нарушением порядка их следования при передаче по сети. Поскольку в TCP не поддерживается отрицательное квитирование, принимающая сторона не может явно указать на необходимость повторной передачи недостающих данных. Вместо этого она повторно отсылает подтверждение для последнего успешно принятого байта (обратите внимание на то, что таблица иллюстрирует ситуацию, когда принимающая сторона не игнорирует сегменты, нарушающие очередность).

Из за большого объема этот материал размещен на нескольких страницах:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76