Поскольку транспортные протоколы обычно используют окно большего размера, мы обсудим буферизацию более подробно. Так как у хоста может быть несколько соединений, каждое из которых обрабатывается отдельно, для раздвижных окон ему может потребоваться большое буферное пространство. Буферы должны использоваться как отправителем, так и получателем. Отправителю буфер нужен для хранения всех переданных сегментов, для которых еще не пришло подтверждение о доставке, на случай, если эти сегменты потеряются и их придется отправить повторно.
Зная, что отправитель выполняет буферизацию, получатель может использовать свои буферы как посчитает нужным. Например, он может содержать единый буферный накопитель для всех соединений. Когда приходит сегмент, предпринимается попытка динамически выделить ему новый буфер. Если это удается, то сегмент принимается, в противном случае он отвергается. Отправитель готов к тому, чтобы передавать потерянные сегменты повторно, и это игнорирование сегментов не наносит большого вреда, хотя расходует некоторые ресурсы. Отправитель просто повторяет попытки до тех пор, пока не получит подтверждение.
Выбор компромиссного решения между буферизацией на сторонах отправителя и получателя зависит от типа трафика. В случае неинтенсивного и нестабильного трафика, например, когда пользователь производит клавиатурный ввод на удаленном компьютере, лучше не выделять никаких буферов, а получать их динамически на обоих концах, полагаясь на буферизацию со стороны отправителя (на случай, если сегменты будут случайно удалены). С другой стороны, в случае передачи файла будет лучше, если получатель выделит целое окно буферов, чтобы данные могли передаваться с максимальной скоростью. Такую стратегию использует TCP.
Тем не менее открытым остается вопрос об организации набора буферов. Когда большинство сегментов примерно одинакового размера, логично организовать буферы в виде массива буферов равной величины, каждый из которых может вместить один сегмент (илл. 6.15 (а)). Но если сегменты сильно отличаются по размеру, от коротких запросов на загрузку веб-страниц до крупных пакетов при одноранговой передаче файлов, массив из буферов фиксированного размера окажется неудобным. Если буфер будет равен наибольшему возможному сегменту, то при хранении небольших сегментов память будет расходоваться неэффективно. Если же он будет меньше, тогда для хранения большого сегмента потребуется несколько буферов с сопутствующими сложностями.
Илл. 6.15. Организация набора буферов. (а) Цепочка буферов фиксированного размера. (б) Цепочка буферов переменного размера. (в) Один большой циклический буфер для одного соединения
Другой способ решения проблемы состоит в использовании буферов переменного размера (илл. 6.15 (б)). Преимущество этого метода заключается в оптимальном использовании памяти, но платой за это является более сложное управление буферами. Третий вариант состоит в выделении соединению единого большого циклического буфера (илл. 6.15 (в)). Эта простая и изящная схема работает независимо от размера сегментов, однако она эффективно использует память, только если все соединения сильно нагружены.
При открытии и закрытии соединений и при изменении формы трафика отправитель и получатель должны динамически изменять выделенные буферы. Следовательно, транспортный протокол должен позволять отправителю отправлять запросы на выделение буфера на другой стороне. Буферы могут выделяться для каждого соединения или коллективно на все соединения между двумя хостами. В качестве альтернативы запросам получатель, зная состояние своих буферов, но не зная, какой трафик ему будет предложен, может сообщить отправителю, что он зарезервировал для него Х буферов. При увеличении числа открытых соединений может потребоваться уменьшить количество или размеры выделенных буферов. Протокол должен предоставлять такую возможность.
В отличие от протокола раздвижного окна, описанного в главе 3, для реализации динамического выделения буферов следует отделить буферизацию от подтверждений. Динамическое выделение буферов на деле означает использование окна переменного размера. Сначала отправитель запрашивает определенное число буферов согласно своим потребностям. Получатель выделяет столько, сколько может. При отправлении каждого сегмента отправитель должен уменьшать число буферов на единицу, а когда оно достигнет нуля, он должен остановиться. Получатель отправляет обратно на попутных сегментах отдельно подтверждения и сведения об имеющихся у него свободных буферах. Эта схема используется в TCP; при этом информация о буферах хранится в поле заголовка Window size (Размер окна).