Осуществление гарантированной доставки данных протоколом TCP является многогранной задачей. С точки зрения сетевых ресурсов, как было показано ранее, гарантированная доставка обеспечивается реализацией следующих функций: нумерация сегментов, алгоритм «скользящее окно», сегменты подтверждения АСК, таймер и вычисление контрольной суммы длины сегмента. Однако, не стоит забывать еще об одном ресурсе, где в процессе передачи могут возникнуть определенные проблемы, способные негативно повлиять на качество обслуживания - буфер между транспортным и прикладным уровнями.

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

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

В протоколе TCP реализована функция «управления потоком» (flow control), позволяющая настраивать скорость поступления данных в буфер ресивера в зависимости от скорости передачи данных прикладному уровню. Управление скоростью, на которой данные поступают в буфер ресивера, осуществляется путем уменьшения (throttling, дословно - душение) скорости передачи сегментов передатчиком.

Принимая во внимание еще такую базовую функцию TCP, как «управление перегрузкой» (congestion control), рассматриваемую подробно ниже и базирующуюся также на принудительном снижении скорости передачи передатчика TCP, можно предположить, что обе функции в об-щем-то адекватны и между ними нет никакой существенной разницы. Однако это не так и стоит уделить особое внимание пониманию их различия. Для этого сначала рассмотрим функцию «управления потоками».

Функция «управления потоками» реализуется при помощи алгоритма «скользящее окно». Далее для простоты понимания предположим, что рассматриваемая реализация протокола TCP на стороне ресивера не поддерживает буферизацию сегментов, пришедших вне очереди. Введем ряд понятий, необходимых для дальнейшего рассмотрения механизмов управления перегрузками, реализованных в протоколе TCP [RFC2581J:

• «окно приемника» (rwnd - Receiver Window): количество данных, которое приемник может принять подряд;

• «TCP-окно» или «окно перегрузки» (cwnd - Congestion Window): размер cwnd ограничивает количество данных, которое источник может послать приемнику без подтверждения доставки;

• «начальный размер окна» (iw - Initial Window): размер окна cwnd после завершения процедуры установления соединения

(three-way handshake, см. выше);

• flight data (датее - DacalnFlight): количество посланных и еще не подтвержденных данных.

Рассмотрим поведение окна приемника, размер которого определяет, сколько байт информации может принять ресивер. В связи с тем, что соединение TCP является полнодуплексным, очевидно, что и на стороне источника, и на стороне приемника для каждого соединения TCP должно быть определено окно приемника. Рассмотрим пример передачи файла между двумя хостами. Пусть источником является хост, передающий приемнику файл достаточно большой длины. В ходе установления соединения ресивером для него определяется буфер размером RcvBuffer. Определим два параметра, необходимых для работы с буфером:

• LastByteRead: номер последнего переданного прикладному уровню байта;

• LastByteRcvd: номер последнего поступившего от передатчика в буфер ресивера байта.

В связи с тем, что рассматриваемый буфер не должен переполняться, справедливо записать следующее выражение:

LastByteRcvd - LastByteRead < RcvBuffer.

Размер окна приемника зависит от размера буфера и определяется следующим образом:

rwr.d = RcvBuffer - [LastByteRcvd - LastByteRead] .

Очевидно, что в связи с тем, что разность переменных, вычисляемая в квадратных скобках (далее ее будем называть «остаточной разностью»), постоянно изменяется, значение размера окна приемника также является переменной (см. рис 1.19).

Каким же образом соединение TCP использует переменную rwnd для реализации функции «управления потоками»? Все достаточно просто: приемник должен информировать источник о размере «остаточной разности», т.е. о том, сколько места свободно в буфере в определенный момент времени. Практически это реализуется следующим образом: ресивер в каждом сегменте подтверждения в поле «размер окна приемника» посылает значение параметра rwnd. Изначально, во время установления соединения, ресивер устанавливает значение rwnd, равное размеру буфера RcvBuffer.

В свою очередь, передатчик также должен управлять несколькими переменными, связанными с функцией «управления потоками»:

• ЬазгЗу^еБег^: номер последнего переданного сетевому уровню байта;

• LastЗyteAcked: номер последнего подтвержденного байта.

Важным параметром функционирования «управления потоками» является разность этих двух параметров, т.е. LastЗyteSent -LastЗyteAcked, определяющая количество посланных источником

Графическое представление буфера и окна приемника байтов, но еще неподтвержденных приемником. Очевидно, что если в источнике количество неподтвержденных байтов будет сохраняться меньшим, чем значение параметра то источник может быть уверенным в том, что переполнения в буфере ресивера не произойдет. Таким образом, справедливо записать следующее выражение, которое должно соблюдаться:

Рис. 1.19. Графическое представление буфера и окна приемника байтов, но еще неподтвержденных приемником. Очевидно, что если в источнике количество неподтвержденных байтов будет сохраняться меньшим, чем значение параметра то источник может быть уверенным в том, что переполнения в буфере ресивера не произойдет. Таким образом, справедливо записать следующее выражение, которое должно соблюдаться: ЬазЬВуіеЗепс - ЬазсВусеАскесЗ < гмпсЗ.

Существует один достаточно тонкий момент, который необходимо учесть в протоколе ТСР. Рассмотрим пример, когда в некоторый момент времени на стороне ресивера буфер наполняется полностью, т.е. гип<1 = 0. Ресивер должен сообщить передатчику о количестве байт, которые он может принять, но в данном случае ресивер не может принять ни одного байта. Ресивер информирует об этом передатчик, который, в свою очередь, должен остановить передачу сегментов. Ресивер, по мере освобождения буфера, должен проинформировать передатчик о значении размера окна, отличающегося от нуля.

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

В протоколе TCP для предотвращения подобных ситуаций предусмотрен специальный алгоритм, предполагающий регулярную посылку короткого однобайтного сегмента передатчиком ресиверу. Как только передатчик получает от ресивера информацию, что rwnd = 0, он инициирует передачу служебных сегментов, корректный прием которых должен быть подтвержден сегментами подтверждения, именно в которых ресивер и имеет возможность проинформировать передатчик о размере окна rwnd.

Тсриаяо | Управление трафиком и качество обслужевания в сети | Управление перегрузками в протоколе tcp