Компьютерные сети. 6-е изд. - Эндрю Таненбаум
Шрифт:
Интервал:
Илл. 6.12. Внезапное разъединение с потерей данных
Очевидно, требуется более сложный протокол, позволяющий избежать потери данных. Один из способов состоит в использовании симметричного варианта, при котором каждое направление разъединяется независимо. В этом случае хост может продолжать получать данные даже после того, как сам отправил запрос на разъединение.
Симметричное разъединение подходит для тех случаев, когда у каждой стороны есть фиксированное количество данных для передачи и каждая из них точно знает, когда эти данные заканчиваются. В других случаях определить, что работа окончена и соединение может быть прервано, не так просто. Можно представить себе протокол, в котором хост 1 говорит: «Я закончил передачу. А вы?». Если хост 2 отвечает: «Я тоже. До свидания», соединение можно безо всякого риска разъединять.
К сожалению, этот протокол работает не всегда. Существует знаменитая проблема «двух армий» (two-army problem). Представьте, что армия белых находится в долине (илл. 6.13). На возвышенностях по обеим сторонам долины расположились две армии синих. Белая армия больше, чем любая из синих, но вместе синие превосходят белых. Если одна из армий синих атакует белых в одиночку, она потерпит поражение, но если синие сумеют атаковать белых одновременно, они могут победить.
Армии синих хотели бы синхронизировать свое выступление. Однако единственный способ связи состоит в отправке связного пешком по долине, где он может быть схвачен, а донесение потеряно (то есть приходится пользоваться ненадежным каналом). Спрашивается: существует ли протокол, позволяющий армиям синих победить?
Предположим, командир 1-й армии синих отправляет следующее сообщение: «Я предлагаю атаковать 29 марта, на рассвете. Сообщите ваше мнение». Теперь предположим, что сообщение успешно доставляется и что командир 2-й армии синих соглашается, а его ответ успешно доставляется обратно в 1-ю армию. Состоится ли атака? Вероятно, нет, так как командир 2-й армии не уверен, что его ответ получен. Если нет, то 1-я армия синих не будет атаковать, и было бы глупо с его стороны в одиночку ввязываться в сражение.
Теперь улучшим протокол с помощью «тройного рукопожатия». Инициатор оригинального предложения должен подтвердить ответ. Если исходить из предположения, что сообщения не теряются, то 2-я армия синих получит подтверждение, но теперь будет сомневаться командир 1-й армии синих. Он не знает, было ли доставлено его подтверждение, а ведь если оно не доставлено, то 2-я армия не будет атаковать. Протокол четырехкратного «рукопожатия» здесь также не поможет.
В действительности можно доказать, что протокола, решающего данную проблему, не существует. Предположим, что такой протокол все же есть. В этом случае последнее сообщение протокола либо является важным, либо нет. Если оно не является важным, удалим его (а также все остальные несущественные сообщения), пока не останется протокол, в котором все сообщения являются существенными. Что произойдет, если последнее сообщение не дойдет до адресата? Мы только что решили, что сообщение является важным, поэтому если оно потеряется, атака не состоится. Поскольку отправитель последнего сообщения никогда не сможет быть уверенным в его получении, он не станет рисковать. Другая синяя армия это знает и также воздержится от атаки.
Чтобы увидеть, какое отношение проблема «двух армий» имеет к разрыву соединения, просто замените слово «атаковать» на «разъединить». Если ни одна сторона не может разорвать соединение до тех пор, пока она не уверена, что другая сторона также готова к этому, то разъединения не произойдет никогда.
Илл. 6.13. Проблема «двух армий»
На практике, чтобы справиться с этой ситуацией, нужно отказаться от идеи договоренности и переложить ответственность на пользователей, чтобы каждая сторона принимала независимое решение о том, когда будет выполнена операция. Такую проблему решить проще. На илл. 6.14 показаны четыре сценария разъединения, использующих «тройное рукопожатие». Этот протокол не является безошибочным, но обычно он работает успешно.
На илл. 6.14 (а) показан нормальный случай, при котором пользователь отправляет DR (DISCONNECTION REQUEST), чтобы инициировать разрыв соединения. Когда запрос доставляется, получатель также отвечает сегментом DR и включает таймер на случай его потери. Когда запрос прибывает, первый пользователь отправляет в ответ на него сегмент ACK и разрывает соединение. Наконец, когда ACK приходит, получатель также разрывает соединение. Разъединение означает, что транспортная подсистема удаляет информацию об этой связи из своей таблицы открытых соединений и сигнализирует о разрыве владельцу соединения (потребителю транспортной службы). Эта процедура отличается от применения пользователем примитива DISCONNECT.
Если последний сегмент ACK теряется (илл. 6.14 (б)), ситуацию спасает таймер. Когда время истекает, соединение разрывается в любом случае.
Теперь рассмотрим случай потери второго DR. Пользователь, инициировавший разъединение, не получит ожидаемого ответа, у него истечет время ожидания, и он начнет все сначала. На илл. 6.14 (в) показано, как это происходит, если все последующие запросы и подтверждения успешно доходят до адресатов.
Последний сценарий (илл. 6.14 (г)) аналогичен предыдущему с одной лишь разницей: в этом случае предполагается, что все повторные попытки передать DR также терпят неудачу, поскольку все сегменты теряются. После N попыток отправитель, наконец, сдается и разрывает соединение. Тем временем у получателя также истекает время, и он тоже отсоединяется.
Хотя такого протокола обычно бывает вполне достаточно, теоретически он может ошибиться, если потеряются изначальный DR и все N повторных передач. Отправитель сдается и разрывает соединение, тогда как другая сторона ничего не знает о попытках разорвать связь и сохраняет активность. В результате получается полуоткрытое соединение, что недопустимо.
Этой ситуации можно избежать, если не позволить отправителю сдаваться после N повторных передач, а заставить его продолжать попытки, пока не будет получен ответ. Однако если другой стороне будет разрешено разрывать связь по таймеру, тогда отправитель действительно будет вечно повторять попытки, так как ответа он не получит никогда. Если же получателю также не разрешать разрывать соединение по таймеру, то протокол зависнет в ситуации, изображенной на илл. 6.14 (г).
Илл. 6.14. Четыре сценария разрыва соединения. (а) Нормальный случай «тройного рукопожатия». (б) Потеряно последнее подтверждение. (в) Потерян ответ. (г) Потерян ответ и последующие запросы разъединения
Чтобы избавиться от полуоткрытых соединений, используется правило, гласящее, что если по соединению в течение определенного времени не приходит ни одного сегмента, оно автоматически разрывается. Таким образом, если одна сторона разорвет соединение, другая обнаружит отсутствие активности и также отсоединится. Правило работает и в тех случаях, когда соединение разрывается не по инициативе одной из сторон, а по причине невозможности передачи пакетов между этими хостами в сети.
Для реализации этого правила каждая сторона
Поделиться книгой в соц сетях:
Обратите внимание, что комментарий должен быть не короче 20 символов. Покажите уважение к себе и другим пользователям!