Шрифт:
На илл. 3.15 показан пример для окна с максимальным размером 1. Вначале фреймов в окне нет, поэтому оно пустое и его верхний и нижний края совпадают, однако с течением времени ситуация меняется. В отличие от окна отправителя, окно получателя всегда сохраняет первоначальный размер, сдвигаясь по мере приема и передачи на сетевой уровень очередного фрейма.
3.4.2. Примеры дуплексных протоколов раздвижного окна
Теперь рассмотрим пример простого однобитного протокола раздвижного окна, а также протоколы, способные обеспечить повторную передачу ошибочных фреймов в случае передачи сразу нескольких фреймов.
Однобитное раздвижное окно
Прежде чем рассматривать общий случай, изучим протокол раздвижного окна, равного 1. Такой протокол использует метод ожидания: отослав фрейм, отправитель должен дождаться подтверждения, прежде чем послать следующий фрейм.
Данный протокол показан на илл. 3.16. Как и другие протоколы, он начинается с определения некоторых переменных. Переменная next_frame_to_send содержит номер фрейма, который отправитель пытается послать. Аналогично переменная frame_expected хранит номер фрейма, ожидаемого получателем. В обоих случаях возможными значениями могут быть только 0 и 1.
/* Протокол 4 (раздвижное окно) является дуплексным
#define MAX_SEQ 1 /* в протоколе 4 должно быть равно 1
typedef enum {frame_arrival, cksum_err, timeout} event_type;
#include "protocol.h"
void protocol4 (void)
{
seq_nr next_frame_to_send; /* только 0 или 1 */
seq_nr frame_expected; /* только 0 или 1 */
frame r, s; /* временные переменные */
packet buffer; /* текущий отправленный пакет */
event_type event;
next_frame_to_send = 0; /* номер следующего фрейма в исходящем потоке */
frame_expected = 0; /* номер ожидаемого фрейма */
from_network_layer(&buffer); /* получить первый пакет у сетевого уровня */
s.info = buffer; /* подготовить первый фрейм для передачи */
s.seq = next_frame_to_send; /* вставить порядковый номер во фрейм */
s.ack = 1 – frame_expected; /* подтверждение, вложенное во фрейм данных */
to_physical_layer(&s); /* передать фрейм */
start_timer(s.seq); /* запустить таймер ожидания подтверждения */
while (true) {
wait_for_event(&event); /* ждать события frame_arrival, cksum_err или timeout */
if (event == frame_arrival) { /* фрейм пришел в целости */
from_physical_layer(&r); /* получить пришедший фрейм */
if (r.seq == frame_expected) { /* обработать входящий поток фреймов */
to_network_layer(&r.info); /* передать пакет сетевому уровню */
inc(frame_expected); /* инвертировать порядковый номер фрейма, ожидаемого в следующий раз */
}
if (r.ack == next_frame_to_send) { /* обработать исходящий поток фреймов */
stop_timer(r.ack); /* остановить таймер */
from_network_layer(&buffer); /* получить следующий пакет у сетевого уровня */
inc(next_frame_to_send); /* инвертировать порядковый номер посылаемого фрейма */
}
}
s.info = buffer; /* подготовить фрейм для передачи */
s.seq = next_frame_to_send; /* вставить порядковый номер во фрейм */
s.ack = 1 – frame_expected; /* порядковый номер последнего полученного фрейма */
to_physical_layer(&s); /* передать фрейм */
start_timer(s.seq); /* запустить таймер ожидания подтверждения */
}
}
Илл. 3.16. Однобитный протокол раздвижного окна
В обычной ситуации только один канальный уровень может начинать передачу. Другими словами, лишь одна из программ должна содержать обращения к процедурам to_physical_layer и start_timer вне основного цикла. Отправитель получает первый пакет от своего сетевого уровня, создает из него фрейм и посылает его. Когда этот (или другой) фрейм приходит, получающий канальный уровень проверяет, не является ли он дубликатом, аналогично протоколу 3. Если это тот фрейм, который ожидался, он передается сетевому уровню и окно получателя сдвигается вверх.