Протокол сетевого уровня IP предоставляет транспортному уровню службу ненадежной передачи данных
Протокол сетевого уровня IP предоставляет транспортному уровню службу ненадежной передачи данных. IP не дает гарантий относительно доставки дейтаграмм, сохранения порядка их следования и корректности информации. При перегрузке маршрутизаторов дейтаграммы могут быть потеряны, порядок их получения может отличаться от порядка отправки, и, кроме того, допускаются искажения битов (изменения значений с 0 на 1 и наоборот). Поскольку дейтаграммы являются средством передачи сегментов транспортного уровня, последний сталкивается с перечисленными проблемами.
Тем не менее протокол TCP способен обеспечить надежную передачу данных, используя службы ненадежной передачи протокола IP. TCP гарантирует, что данные, которые процесс считывает из своего TCP-буфера, не содержат искажений, пропусков и дублирований, а также расположены в правильном порядке. Другими словами, входной поток принимающей стороны в точности совпадает с выходным потоком передающей стороны. Ниже мы увидим, каким образом TCP обеспечивает подобные гарантии. Оказывается, в основе его функционирования лежат многие из принципов, описанных в предыдущем разделе этой главы.
Простым и удобным механизмом, которым мы пользовались при построении собственного протокола надежной передачи данных, является связывание каждого переданного неподтвержденного сегмента с индивидуальным таймером. На практике управление таймерами оказывается далеко не столь тривиальным, и в RFC 2988 рекомендуется использовать единственный таймер для всех сегментов, которые должны быть квитированы. Эта рекомендация учитывается и в протоколе TCP.
Изучение механизма надежной передачи данных в TCP будет происходить в два этапа. Сначала мы рассмотрим упрощенную модель передающей стороны TCP, в которой интервалы ожидания являются единственным средством обнаружения потерь пакетов. Затем мы усложним модель, введя в нее механизм дублирования подтверждений. При этом мы будем опираться на предположение о том, что передача данных ведется в одном направлении, от хоста А к хосту В, и объем передаваемых данных значителен (например, хост А посылает файл большого размера).
Упрощенная программа на псевдоязыке для передающей стороны приведена ниже. В ней обрабатываются три события, связанные с передачей данных: получение новых данных от верхнего уровня, истечение интервала ожидания и получение подтверждения (АСК). При наступлении первого из событий данные заключаются в сегмент, который затем передается протоколу IP. Каждый сегмент содержит порядковый номер, равный номеру первого байта данных в нем. Кроме того, если таймер не был запущен ранее для какого-либо сегмента, в момент передачи текущего сегмента протоколу IP происходит его запуск (представьте себе, что таймер связан с самым «старым» неподтвержденным сегментом). Интервал ожидания Timeoutlnterval, устанавливаемый для таймера, вычисляется по формуле, приведенной выше.
/* Предполагается, что передающая сторона не ограничивает поток данных и не контролирует перегрузки; объем данных, передаваемый верхним уровнем, меньше величины MSS; передача ведется в одном направлении. */
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 также обладают неявным отрицательным квитированием: существует механизм ускоренной повторной передачи, который действует следующим образом. Получение трех одинаковых квитанций для сегмента является признаком потери следующего за ним сегмента и вызывает повторную передачу последнего до истечения интервала ожидания. Для обнаружения потерь и дублирований сегментов в TCP используются порядковые номера. Как и наш протокол rdt 3.0, протокол TCP не способен различать потери, задержки и искажения сегментов и их квитанций. Во всех случаях передающая сторона реагирует на это одним и тем же действием — повторной передачей сегмента.
В протоколе TCP используется механизм конвейеризации, то есть передаются несколько сегментов без ожидания квитанции для каждого из них. Мы убедились в том, что конвейеризация может значительно повысить коэффициент полезности, если отношение времени передачи одного сегмента ко времени оборота мало. Число сегментов, которые могут быть переданы без ожидания квитанций, определяется механизмами контроля потоков данных и перегрузки. Мы рассмотрим механизм контроля потоков в конце этого раздела; контроль перегрузки будет обсуждаться в разделе «Контроль перегрузок в ТСР». Сейчас нам достаточно просто знать о том, что в протоколе TCP используется конвейеризация.