Выбрать главу

packet buffer;                   /* буфер для исходящего пакета */

event_type event;                /* frame_arrival является единственным возможным событием */

while (true) {

    from_network_layer(&buffer); /* получить у сетевого уровня пакет для передачи */

    s.info = buffer;             /* скопировать его во фрейм s для передачи */

    to_physical_layer(&s);       /* отправка фрейма */

    wait_for_event(&event);      /* не продолжать, пока на это не будет получено разрешения */

}

}

void receiver2(void)

{

frame r, s;                     /* буферы для фреймов */

event_type event;               /* frame_arrival является единственным возможным событием */

while (true) {

     wait_for_event(&event);     /* единственная возможность — прибытие фрейма (событие frame_arrival) */

     from_physical_layer(&r);    /* получить входящий фрейм */

     to_network_layer(&r.info);  /* передать данные сетевому уровню */

     to_physical_layer(&s);      /* передать пустой фрейм, чтобы «разбудить» отправителя */

}

}

Илл. 3.13. Симплексный протокол с ожиданием и остановкой

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

В приведенной выше схеме имеется один критический недостаток. Прежде чем читать дальше, попытайтесь понять, что же неверно в данном варианте протокола.

Чтобы разобраться, что может пойти не так, вспомните, что цель канального уровня заключается в предоставлении безошибочной прозрачной связи между двумя процессами сетевого уровня. Сетевой уровень устройства A передает серию пакетов своему канальному уровню, который должен обеспечить доставку идентичной серии пакетов сетевому уровню устройства B его канальным уровнем. В частности, сетевой уровень B не может распознать потерю или дублирование пакета, поэтому канальный уровень должен гарантировать, что повтора не произойдет ни при каких обстоятельствах.

Рассмотрим следующий сценарий.

1. Сетевой уровень устройства A передает пакет 1 своему канальному уровню. Пакет доставляется в целости на устройство B и передается его сетевому уровню. B посылает фрейм подтверждения обратно на A.

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

3. У канального уровня устройства A внезапно истекает отведенный интервал времени. Не получив подтверждения, оно предполагает, что отправленный им фрейм с данными был поврежден или потерян, и посылает его еще раз.

4. Дубликат фрейма в целости прибывает на канальный уровень B и передается на сетевой уровень. В итоге часть файла, переданного с A на B, дублируется. Копия файла на устройстве B будет неверной, и ошибка не будет обнаружена, другими словами, протокол даст сбой.

Разумеется, необходим некий механизм, с помощью которого получатель смог бы различать новые фреймы и переданные повторно. Наиболее очевидное решение — нумерация фреймов. Отправитель указывает порядковый номер фрейма в его заголовке. Благодаря этому принимающее устройство отличает новый фрейм от дубликата, который необходимо проигнорировать.

Необходимо, чтобы протокол выполнялся без ошибок, а нумерация не занимала много места в заголовке фрейма, поскольку соединение должно использоваться эффективно. Возникает вопрос: каково минимальное количество битов, достаточное для порядкового номера фрейма? В зависимости от протокола можно выделить один или несколько битов (или байтов). Важно, чтобы номера были достаточно большими для правильной работы протокола, иначе он будет бесполезен.

Единственная неопределенность в данном протоколе может возникнуть между фреймом m и следующим за ним фреймом m + 1. Если m потерян или поврежден, получатель не подтвердит его и отправитель повторит передачу. Когда он будет успешно принят, получатель отправит подтверждение. Именно здесь находится источник потенциальной проблемы. В зависимости от наличия подтверждения отправитель дублирует фрейм m или передает новый фрейм m + 1.

На стороне отправителя событием, запускающим передачу фрейма m + 1, является получение подтверждения доставки фрейма m. Но это означает, что фрейм m – 1 уже передан и подтверждение его доставки отправлено и получено. В противном случае протокол не стал бы посылать новый фрейм. Следовательно, неопределенность может возникнуть только между двумя соседними фреймами.

Таким образом, для нумерации фрейма достаточно всего одного бита информации (со значением 0 или 1). В каждый момент времени получатель ожидает прибытия фрейма с определенным порядковым номером. Фрейм с верным номером принимается, передается сетевому уровню, затем отправляется подтверждение его получения. Номер следующего ожидаемого фрейма увеличивается по модулю 2 (то есть 0 становится 1, а 1 — 0). Фрейм с неверным номером отбрасывается как дубликат. Однако последнее подтверждение повторяется, чтобы сообщить отправителю, что фрейм получен полностью.

Пример такого протокола представлен на илл. 3.14. Протокол, в котором отправитель ожидает положительного подтверждения, прежде чем перейти к пере-

/* Протокол 3 (PAR) обеспечивает симплексную передачу данных по ненадежному каналу.

#define MAX_SEQ 1                               /* в протоколе 3 должно быть равно 1 */

typedef enum {frame_arrival, cksum_err, timeout} event_type;

#include "protocol.h"

void sender3(void)

{

seq_nr next_frame_to_send;                     /* порядковый номер следующего исходящего фрейма */

frame s;                                       /* временная переменная */

packet buffer;                                 /* буфер для исходящего пакета */

event_type event;

next_frame_to_send = 0;                        /* инициализация исходящих последовательных номеров */

from_network_layer(&buffer);                   /* получить первый пакет у сетевого уровня */

while (true) {

     s.info = buffer;                           /* сформировать фрейм для передачи */

     s.seq = next_frame_to_send;                /* вставить порядковый номер во фрейм */

     to_physical_layer(&s);                     /* послать фрейм по каналу */

     start_timer(s.seq);                        /* запустить таймер ожидания подтверждения */

     wait_for_event(&event);                    /* ждать событие frame_arrival, cksum_err или timeout */

     if (event == frame_arrival) {

            from_physical_layer(&s);            /* получить подтверждение */

           if (s.ack == next_frame_to_send) {

                 stop_timer(s.ack);             /* остановить таймер

                   from_network_layer(&buffer); /* получить следующий исходящий пакет */

                   inc(next_frame_to_send);     /* инвертировать значение переменной next_frame_to_send */

           }

     }

}

}

void receiver3(void)

{

seq_nr frame_expected;

frame r, s;

event_type event;

frame_expected = 0;

while (true) {

     wait_for_event(&event);                    /* ожидание возможных событий: frame_arrival, cksum_err */

     if (event == frame_arrival) {              /* пришел неповрежденный фрейм */

            from_physical_layer(&r);            /* получить пришедший фрейм */

            if (r.seq == frame_expected) {      /* именно этот фрейм и ожидался */

                  to_network_layer(&r.info);    /* передать данные сетевому уровню */