Порядковые номера и номера подтверждения
Поля порядкового номера и номера подтверждения являются наиболее важными в заголовке ТСР-сегмента, поскольку играют ключевую роль в функционировании службы надежной передачи данных. Однако перед тем, как рассматривать роль этих полей в механизме надежной передачи, обратимся к величинам, которые протокол TCP помещает в эти поля.
Протокол TCP рассматривает данные как неструктурированный упорядоченный поток байтов. Такой подход проявляется в том, что TCP назначает порядковые номера не сегментам, а каждому передаваемому байту. Исходя из этого, порядковый номер сегмента определяется как порядковый номер первого байта этого сегмента. Рассмотрим следующий пример. Пусть хост А желает переслать поток данных хосту В через TCP-соединение. Протокол TCP на передающей стороне неявно нумерует каждый байт потока. Пусть размер передаваемого файла составляет 500 ООО байт, величина MSS равна 1000 байт, и первый байт потока имеет порядковый номер 0. Как показано на рис. 3.27, TCP разбивает поток данных на 500 сегментов. Первому сегменту присваивается порядковый номер 0, второму сегменту — номер 1000, третьему сегменту — номер 2000, и т. д. Порядковые номера заносятся в поля порядковых номеров каждого ТСР-сегмента.
Теперь рассмотрим номера подтверждения. Вспомним о том, что протокол TCP обеспечивает дуплексную передачу данных, то есть через единственное ТСР-со-единение данные между хостами А и В могут передаваться одновременно в обе стороны. Каждый сегмент, исходящий из хоста В, содержит порядковый номер данных, передающихся от хоста В к хосту А. Номер подтверждения, который хост А помещает в свой сегмент, — это порядковый номер следующего байта, ожидаемого хостом А от хоста В. Рассмотрим следующий пример. Предположим, что хост А получил все байты с номерами от 0 до 535, посланные хостом В, и формирует сегмент для передачи хосту В. Хост А ожидает, что следующие байты, посылаемые хостом В, будут иметь номера, начинающиеся с 536, и помещает число 536 в поле номера подтверждения своего сегмента.
Рассмотрим другую ситуацию. Пусть хост А получил от хоста В два сегмента, в первом из которых содержатся байты с номерами от 0 до 535, а во втором — байты с номерами от 900 до 1000. Это означает, что по какой-либо причине байты с номерами от 536 до 899 не были получены хостом А. В этом случае хост А ожидает появления отсутствующих байтов и в поле номера подтверждения своего сегмента помещает число 536. Поскольку TCP квитирует принятые данные до первого отсутствующего байта, говорят, что он поддерживает общее квитирование.
Последний пример демонстрирует очень важный аспект функционирования протокола TCP. Третий сегмент (содержащий байты 900-1000) принят хостом А раньше, чем второй (содержащий байты 536-899), то есть с нарушением порядка следования данных. Возникает вопрос: как протокол TCP реагирует на нарушение порядка? Оказывается, что спецификация протокола предоставляет программистам, реализующим TCP, полную свободу в разрешении этого вопроса. Тем не менее выделяются два основных подхода: принимающая сторона может либо немедленно проигнорировать сегменты, нарушающие порядок следования данных, либо сохранять принятые сегменты до тех пор, пока недостающие данные не будут получены. Первый подход позволяет упростить программирование, в то время как второй повышает эффективность использования линий связи.
На рис. 3.27 первым порядковым номером является 0, однако на практике стороны протокола TCP выбирают начальный номер случайным образом. Это объясняется необходимостью минимизировать вероятность нахождения в сети сегмента, который сформирован другим (уже закрытым) TCP-соединением между этими же двумя хостами, но который может быть по ошибке отнесен к существующему TCP-соединению. Заметим, что существующее соединение может использовать те же номера портов, что и предыдущее.