Решением данной проблемы является предоставление гарантии того, что в сдвинутом положении окно не перекроет исходное окно. Для этого размер окна не должен превышать половины от количества порядковых номеров (это показано на рис. 3.15, в и 3.15, г.) Например, если для порядковых номеров используются 3 бита, они должны изменяться в пределах от 0 до 7. В таком случае, в любой момент времени только четыре кадра могут быть неподтвержденными. Таким образом, если будут получены кадры с 0 по 3 и будет передвинуто окно для приема кадров с 4 по 7, получатель сможет безошибочно отличить повторную передачу (кадры с 0 по 3) от новых кадров (с 4 по 7). Поэтому в протоколе 6 применяется окно размером (MAX_SEQ + 1)/2.
Возникает новый вопрос: сколько буферов должно быть у получателя? Ни при каких условиях он не должен принимать кадры, номера которых не попадают в окно. Поэтому количество необходимых буферов равно размеру окна, а не диапазону порядковых номеров. В приведенном выше примере 3-битовых порядковых номеров требуется четыре буфера с номерами от 0 до 3. Когда прибывает кадр i, он помещается в буфер i mod 4. Обратите внимание на то, что хотя i и (i + 4), взятые по модулю 4, «соревнуются» за один и тот же буфер, они никогда не оказываются в одном окне одновременно, потому что это привело бы к увеличению размера окна, по крайней мере, до 5.
По этой же причине количество необходимых таймеров также равно числу буферов, а не диапазону порядковых номеров. Таким образом, удобно связать каждый таймер со своим буфером. Когда интервал времени истекает, содержимое буфера высылается повторно.
Протокол 6 также ослабляет неявное предположение о том, что загрузка канала довольно высока. Мы сделали это предположение в протоколе 5, в котором подтверждение «ехало верхом» на встречном информационном кадре. Если обратный поток информации невелик, подтверждения могут задерживаться на довольно большой период времени, создавая проблемы. В экстремальной ситуации, если в одном направлении посылается много информации, а во встречном — вообще ничего, протокол останавливается, когда окно отправителя достигает максимума.
В протоколе 6 эта проблема решена. По прибытии последовательного кадра с данными процедура start_ack_timer запускает вспомогательный таймер. Если таймер сработает раньше, чем появится кадр с данными для передачи, то будет послан отдельный кадр с подтверждением. Прерывание от вспомогательного таймера называется событием ack_timeout. При такой организации возможен однонаправленный поток данных, так как отсутствие встречных информационных кадров, на которых можно было бы отправлять подтверждения, больше не является препятствием. Требуется всего один таймер. При вызове процедуры start_ack_timer, если таймер уже запущен, ничего не происходит. Таймер не сбрасывается и не продляется, так как он нужен лишь для обеспечения некоторого минимального количества подтверждений.
Важно, что период времени вспомогательного таймера должен быть существенно короче интервала ожидания подтверждения. При этом условии подтверждение в ответ на полученный правильный кадр должно приходить прежде, чем у отправителя истечет период ожидания, и он пошлет этот кадр второй раз.
Протокол 6 использует более эффективную стратегию обработки ошибок, чем протокол 5. Как только у получателя появляются подозрения, что произошла ошибка, он высылает отправителю отрицательное подтверждение (NAK). Получатель может делать это в двух случаях: если он получил поврежденный кадр или если прибыл кадр с номером, отличным от ожидаемого (возможность потери кадра). Чтобы избежать передачи нескольких запросов на повторную передачу одного и того же кадра, получатель должен запоминать, был ли уже послан NAK для данного кадра. В протоколе 6 для этой цели применяется переменная no_nak, принимающая значение true, если NAK для ожидаемого кадра (с номером frame_expected) еще не был послан. Если NAK повреждается или теряется по дороге, в этом нет большой беды, так как у отправителя, в конце концов, истечет период ожидания положительного подтверждения, и он, так или иначе, вышлет недостающий кадр еще раз. Если после того, как NAK будет выслан и потерян, прибудет не тот кадр, переменной no_nak опять будет присвоено true и будет запущен вспомогательный таймер. Когда время истечет, будет послано положительное подтверждение (ACK) для восстановления синхронизации текущих состояний отправителя и получателя.
В некоторых ситуациях время, необходимое для прохождения кадра по каналу, его обработки и отсылки обратно подтверждения, практически остается неизменным. В таких ситуациях отправитель может поставить время ожидания лишь немного больше ожидаемого интервала между отправкой кадра и получением подтверждения. NAK в таких случаях применять неэффективно.
Однако в других случаях время может сильно варьироваться. Если встречный поток данных нерегулярен, то время прихода подтверждений также будет непостоянным, уменьшаясь при наличии встречного потока и увеличиваясь при его отсутствии. Перед отправителем возникает непростой выбор значения времени ожидания. Если выбрать слишком короткий интервал, то увеличится риск ненужных повторных передач. При выборе слишком большого значения протокол будет тратить много времени на ожидания после ошибки. В обоих случаях пропускная способность на что-то тратится. В целом, если среднеквадратичное отклонение интервала ожидания подтверждения велико по сравнению с самим интервалом, то таймер может быть установлен довольно «свободно», и отрицательные подтверждения могут существенно ускорить повторную передачу потерянных или поврежденных кадров.
С вопросом тайм-аутов и отрицательных подтверждений тесно связана проблема определения кадра, вызвавшего тайм-аут. В протоколе 5 это всегда кадр с номером ack_expected, поскольку он является старшим. В протоколе 6 нет столь простого способа определить кадр, интервал ожидания которого истек. Предположим, были переданы кадры с 0 по 4, то есть список неподтвержденных кадров выглядит так: 01234 (от первого к последнему). Теперь допустим, что у кадра 0 истекает интервал ожидания и он передается повторно, затем посылается кадр 5 (новый), потом интервал ожидания истекает у кадров 1 и 2 и посылается кадр 6 (также новый). В результате список неподтвержденных кадров принимает вид: 3405126, начиная с самого старого и заканчивая самым новым. Если весь встречный поток данных потеряется, интервалы ожидания этих семи кадров истекут именно в таком порядке.
Чтобы не усложнять и без того непростой пример протокола, мы не показываем подробностей управления таймером. Вместо этого предполагается, что переменной oldest_frame при наступлении тайм-аута присваивается номер кадра, интервал времени которого истек.
3.5. Примеры протоколов передачи данных
В пределах одного здания для связи компьютеров широко применяются локальные сети, однако большинство глобальных сетей построено на двухточечных линиях. С локальными сетями мы познакомимся в главе 4. Здесь мы рассмотрим протоколы канального уровня, которые применяются на двухточечных каналах в Интернете в двух наиболее распространенных ситуациях. Первая — это передача пакетов по оптоволокну SONET. Например, такие каналы соединяют маршрутизаторы, установленные в разных концах сети поставщика услуг Интернета.
Вторая ситуация описывает каналы ADSL в пределах локального контура телефонной сети. Такие связи соединяют с Интернетом миллионы отдельных пользователей и компаний.
Пользователям необходимы для подключения к Интернету такие двухточечные связи, а также телефонные модемы, арендованные линии, кабельные модемы и т. д. Для пересылки пакетов по таким каналам используется стандартный протокол под названием PPP (Point-to-Point Protocol, протокол двухточечного соединения). Протокол PPP описан в стандарте RFC 1661 и доработан в более поздних документах RFC 1662 и др. (Simpson, 1994a, 1994b). PPP применяется в каналах SONET и ADSL, но по-разному.