Тайм-ауты и повторные передачи TCP

         

Отправка 16 пакетов размером 512 байт через четыре маршрутизатора



Рисунок 24.4 Отправка 16 пакетов размером 512 байт через четыре маршрутизатора.


Это передача займет больше отрезков времени, однако каждый отрезок короче, так как отправляются пакеты меньшего размера.

[(512 + 40 байт) x 8 бит/байт]/1544000 бит/сек = 2,9 миллисекунды на пересылку

Сейчас полное время составляет (18 x 2,9) = 52,2 миллисекунды. Каждый канал снова не занят в течение двух отрезков времени, что сейчас составляет 5,8 миллисекунды.

В этом примере мы игнорировали время, которое необходимо для того, чтобы вернулось подтверждение (ACK), также мы проигнорировали время, необходимое для установления и разрыва соединения, и не приняли во внимание то, что по каналам может двигаться и другой траффик. Тем не менее, расчеты в [Bellovin 1993] указывают, что отправка больших пакетов всегда эффективней. Однако, для различных сетей требуются более подробные исследования.



Отправка 32768 байт данных от slip на vangogh



Рисунок 21.6 Отправка 32768 байт данных от slip на vangogh.


На рисунке 21.6 мы сразу видим три повторные передачи в моменты времени 10, 14 и 21. Во всех трех случаях только один сегмент передается повторно, потому что только одна точка оказалась ниже предыдущих.

Давайте рассмотрим первый из этих "скачков вниз" (в момент времени 10). Вывод команды tcpdump мы рассмотрим вместе с рисунком 21.7.



Отправка двух пакетов размером 4096 байт через четыре маршрутизатора



Рисунок 24.3 Отправка двух пакетов размером 4096 байт через четыре маршрутизатора.


Основная проблема заключается в том, что маршрутизаторы это устройства, которые работают по принципу "сохранить и перенаправить". Они обычно получают входящий пакет целиком, проверяют на правильность IP заголовок, включая контрольную сумму IP, принимают решение о маршрутизации и затем начинают отправку исходящего пакета. На этом рисунке мы предположили идеальный случай, когда на операции, осуществляемые в маршрутизаторе, время не тратится, (горизонтальные пунктирные линии). Тем не менее, на отправку всех 8192 байт от R1 до R4 будет истрачено четыре отрезка времени. Время на каждую пересылку будет составлять

[(4096 + 40 байт) x 8 бит/байт]/1544000 бит/сек = 21,4 миллисекунды на пересылку

(IP и TCP заголовки составляют 40 байт.) Полное время, которое тратится на отправку данных, состоит из количества пакетов плюс количество пересылок минус один и составляет четыре отрезка времени или 85,6 миллисекунды. Каждый канал остается неиспользованным в течение двух отрезков времени или 42,8 миллисекунды.

На рисунке 24.4 показано что произойдет, если мы пошлем 16 пакетов размером 512 байт.





Отправка файла размером 1 Мбайт по сетям с 30миллисекундной латенсией



Рисунок 24.6 Отправка файла размером 1 Мбайт по сетям с 30-миллисекундной латенсией.


На рисунке 24.6 показано состояние обеих сетей через 30 миллисекунд. В обеих сетях первый бит данных достиг удаленного конца через 30 миллисекунд (латенсия), однако в случае сети T1 (емкость канала - 5790 байт), 994210 байт все еще находятся у отправителя, ожидая того, что они будут отправлены. Емкость гигабитной сети, составляет 3750000 байт, поэтому файл целиком занимает всего лишь около 25% канала. Последний бит файла достигает получателя через 8 миллисекунд после первого бита.

Полное время передачи файла по сети T1 составляет 5,211 секунды. Если мы увеличить ширину полосы пропускания, например, с использованием сети T3 (45000000 бит/сек), полное время уменьшится до 0,208 секунды. Увеличение ширины полосы в 29 раз уменьшает полное время в 25 раз.

В случае гигабитной сети полное время, необходимое на передачу файла, составляет 0,038 секунды: 30-миллисекундная латенсия плюс 8 миллисекунд на реальную передачу файла. Предположим, мы можем увеличить ширину полосы пропускания до 2 гигабит/сек, однако в этом случае мы уменьшим полное время передачи до всего лишь 0,034 секунды: та же самая 30-миллисекундная латенсия плюс 4 миллисекунды на передачу файла. Таким образом, удвоение полосы передачи, уменьшает полное время всего лишь на 10%. В случае гигабитных скоростей мы уже ограничены латенсией, а не шириной полосы.

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



Отправка команды от клиента к серверу с использованием линейного режима Telnet



Рисунок 26.14 Отправка команды от клиента к серверу с использованием линейного режима Telnet.


Если мы сравним это с той же самой командой, вводимой в Rlogin (рисунок 19.2), то увидим, что линейный режим Telnetа использует два сегмента (один с данными и один для подтверждения, что в целом составляет 86 байт, включая IP и TCP заголовки), тогда как Rlogin использует 15 сегментов (5 с введенными данными, 5 с отраженными эхом данными, 5 с подтверждениями, всего 611 байт). Нетрудно догадаться, в чью пользу это сравнение!

Что если на сервере мы запустим приложение, которое требует использовать режим единственного символа? (Например, редактор vi.) В этом случае будет происходить следующее.

Когда приложение стартует на сервере и изменяет режим своего псевдотерминала, Telnet сервер уведомляется о том, что требуется режим единственного символа. Сервер посылает WILL ECHO клиенту вместе с подопцией линейного режима, которая сообщает клиенту о том, что не нужно составлять полные строки, а вместо этого необходимо посылать один символ за один раз. Клиент отвечает DO ECHO и подтверждает подопцию линейного режима. Приложение запускается на сервере. Каждый символ, который мы печатаем, отправляется серверу сам по себе (естественно используется алгоритм Нагла), при этом сервер не требует отражения эхом. Когда приложение завершает работу и восстанавливает режим псевдотерминала, об этом уведомляется Telnet сервер. Сервер отправляет WONT ECHO клиенту вместе с подопцией линейного режима, которая сообщает клиенту о необходимости снова составлять полные строки. Клиент отвечает DONT ECHO и подтверждает подопцию линейного режима.

Отличие этого сценария от того, который реализуется при вводе пароля, показывает, что функция отражения эхом и символ за один раз, а также строка за один раз, это независимые характеристики. Когда мы вводим пароль, эхо должно быть отключено, при этом активизирован режим строка за один раз. Для полноэкранных приложений, таких как редакторы, эхо отключается и требуется режим символ за один раз.

На рисунке 26.15 показаны различные режимы, которые мы видели для Telnet и Rlogin.

Приложение Клиент посылает Эхо клиента? Пример
символ за раз строка за раз
Rlogin · нет
Telnet, символ за раз · нет
Telnet, линейный режим · да обычные команды
Telnet, линейный режим · нет ввод пароля
Telnet, линейный режим · нет редактор vi


Пакеты "оставайся в живых" которые определяют что хост вышел из строя



Рисунок 23.1 Пакеты "оставайся в живых", которые определяют, что хост вышел из строя.

В строках 1, 2 и 3 отправляется строка "hello, world" от клиента к серверу и обратно. Первая проба "оставайся в живых" появляется через 2 часа (7200 секунд) в строке 4. Первое на что необходимо обратить внимание - это ARP запрос и ARP отклик перед отправкой TCP сегмента в строке 6. На пробу "оставайся в живых" в строке 6 приходит отклик с удаленного конца (строка 7). Тот же обмен пакетами происходит через 2 часа в строках 8-11.

Если бы мы могли видеть все поля в пробах "оставайся в живых" (строки 6 и 10), то обязательно обратили бы внимание на то, что поле номера последовательности на единицу меньше чем следующий отправляемый номер последовательности, который должен быть отправлен (в данном примере 13, тогда как должен быть 14). Так как в сегменте нет данных, tcpdump не печатает поле номера последовательности. (Программа tcpdump печатает номер последовательности для пустых сегментов, только в том случае если они содержат флаги SYN, FIN или RST.) Именно прием этих неверных номеров последовательности заставляет TCP модуль сервера отвечать подтверждениями на пробы "оставайся в живых". В отклике клиенту сообщается следующий номер последовательности, которую ожидает сервер (14).

Некоторые более старые реализации, основанные на 4.2BSD, не отвечают откликом на пробы "оставайся в живых", если сегмент не содержит данных. Некоторые системы могут быть сконфигурированы так, чтобы посылать в пробе один байт данных, чтобы получить на него отклик. Этот байт не принесет никакого вреда, потому что это не ожидаемый байт (байт, который получатель уже ранее получил и подтвердил), поэтому он отбрасывается получателем. Другие системы посылают сначала сегмент в стиле 4.3BSD (без данных) в качестве пробы, и если отклик не получен, переключаются на сегменты в стиле 4.2BSD.

Затем мы отсоединили кабель и ожидаем, что на следующую пробу (а именно через 2 часа) отклик не будет получен. Когда появляется следующая проба, мы никогда не увидим TCP сегменты в кабеле, потому что хост не отвечает на ARP запросы. Все же мы видим, что клиент отправляет 10 проб, с промежутком в 75 секунд, перед тем как прекратить попытки. Из нашего интерактивного скрипта мы видим, что код ошибки, возвращенный процессу клиента от TCP модуля, транслируется в сообщение "Connection timed out" (соединение закрыто по тайм-ауту).



PAWS защита от перехода номеров последовательности через ноль



PAWS: защита от перехода номеров последовательности через ноль

Представим TCP соединение, использующее опцию масштабирования окна, с максимально возможным окном, 1 гигабайт (230). (Самое большое окно даже меньше чем это, 65535 x 214, а не 216 x 214, однако это не должно влиять на наши рассуждения.) Также представьте, что используется опция временной марки, и что значение временной марки, назначенное отправителем, увеличивается на единицу для каждого отправляемого окна. (Это достаточно устаревший способ. Обычно значение временной марки увеличивается значительно быстрее.) На рисунке 24.8 показан поток данных между двумя хостами, возникающий при передаче 6 гигабайт. Чтобы избежать большого количества десятизначных цифр, мы используем запись G, что означает умножение на 1.073.741.824. Мы также используем форму записи из tcpdump, где J:K означает байты от J до K-1, включая байт K-1.

Время Отправленные байты Отправленный номер последова-тельности Отправлен-ная временная марка Получение
A 0G:1G 0G:1G 1 принято нормально
B 1G:2G 1G:2G 2 принято нормально, но один сегмент потерян и передан повторно
C 2G:3G 2G:3G 3 принято нормально
D 3G:4G 3G:4G 4 принято нормально
E 4G:5G 0G:1G 5 принято нормально
F 5G:6G 1G:2G 6 принято нормально, но повторно переданный сегмент появился в сети повторно


Передача 6 гигабайт в шести 1гигабайтных окнах



Рисунок 24.8 Передача 6 гигабайт в шести 1-гигабайтных окнах.

32-битный номер последовательности перешел через ноль между моментами времени D и E. Мы предположили, что один сегмент потерялся в момент времени B и был передан повторно. Также мы предположили, что потерянный сегмент повторно появился в сети в момент времени F.

Разница во времени между моментами, когда сегмент был потерян и появился повторно, меньше чем MSL; иначе сегмент должен быть отброшен каким-либо маршрутизатором по истечению его TTL. Как мы упоминали ранее, такая проблема возникает только на высокоскоростных соединениях, где старые сегменты могут повторно появиться и содержать номер последовательности, который в настоящее время передается.

Также мы можем видеть из рисунка 24.8, что использование временной марки решает эту проблему. Получатель рассматривает временную марку как 32-битное расширение к номеру последовательности. Так как потерянный сегмент, повторно появившийся в момент времени F, имел временную марку равную 2, что меньше чем самая последняя приемлемая временная марка (5 или 6), он отбрасывается алгоритмом PAWS.

Алгоритм PAWS не требует какой-либо формы синхронизации времени между отправителем и получателем. Все что необходимо получателю это то, чтобы значение временной марки монотонно увеличивалось и увеличивалось по крайней мере на единицу для каждого нового окна.



Передача текстовых файлов представление NVT ASCII или двоичное?



Передача текстовых файлов: представление NVT ASCII или двоичное?

Давайте убедимся в том, что при передаче текстовых файлов по умолчанию используется формат NVT ASCII. В этот раз мы не будем использовать флаг -d, поэтому мы не увидим команды клиента, однако клиент все еще печатает отклики от сервера:


sun % ftp bsdi
Connected to bsdi.
220 bsdi FTP server (Version 5.60) ready.

Name (bsdi:rstevens): вводим RETURN
331 Password required for rstevens.

Password: вводим пароль
230 User rstevens logged in.

ftp> get hello.c получаем файл
200 PORT command successful.

150 Opening ASCII mode data connection for hello.c (38 bytes).
226 Transfer complete. сервер сообщает, что файл содержит 38 байт

local: hello.c remote: hello.c вывод от клиента
42 bytes received in 0.0037 seconds (11 Kbytes/s) 42 байта пришло по соединению данных

ftp> quit
221 Goodbye.

sun % ls -l hello.c
-rw-rw-r-- 1 rstevens 38 Jul 18 08:48 hello.c однако файл содержит 38 байт

sun % wc -l hello.c подсчет строк в файле
4 hello.c

Сорок два байта было передано по соединению данных, потому что файл содержит четыре строки. Каждый Unix символ новой строки (\n) конвертируется в 2-байтную последовательность NVT ASCII конец строки (\r\n) сервером для передачи, а затем конвертируется обратно клиентом при записи на диск.

Более новые клиенты стараются определить, используется ли подобная система на сервере, и если да, передают файлы в двоичном виде (image тип файла) вместо ASCII. Это помогает в двух случаях. Отправитель и получатель не должны просматривать каждый байт (это большая экономия времени и ресурсов). Передается меньше байт, если операционная система хоста использует меньше байтов в качестве символа конца строки, нежели 2-байтовая последовательность NVT ASCII (это меньшая часть экономии).

Мы можем увидеть подобную оптимизацию с использованием BSD/386 клиента и сервера. Включен отладочный режим, что позволяет увидеть команды FTP клиента:


bsdi % ftp -d slip указываем опцию -d, чтобы видеть команды клиента
Connected to slip.
220 slip FTP server (Version 5.60) ready.

Name (slip:rstevens): вводим RETURN
---> USER rstevens
331 Password required for rstevens.

Password: вводим пароль
---> PASS XXXX
230 User rstevens logged in.

---> SYST это клиент посылает автоматически
215 UNIX Type: L8 Version: BSD-199103 отклик сервера

Remote system type is UNIX. вывод информации клиентом
Using binary mode to transfer files. вывод информации клиентом

ftp> get hello.c получить файл
---> TYPE I это клиент посылает автоматически
200 Type set to I.

---> PORT 140,252,13,66,4,84 номер порта = 4 х 256 + 84 = 1108
200 PORT command successful.

---> RETR hello.c
150 Opening BINARY mode data connection for hello.c (38 bytes).
226 Transfer complete.

38 bytes received in 0.035 seconds (1.1 Kbytes/s) в этот раз только 38 байт

ftp> quit

---> QUIT
221 Goodbye.

После того как мы правильно ввели имя и пароль серверу, FTP клиент автоматически посылает команду SYST, в ответ на которую сервер сообщает свой тип системы. Если отклик начинается со строки "215 UNIX Type: L8", и если клиент работает под управлением Unix системы с 8-битными байтами, для передачи всех файлов используется двоичный (image) режим, если его не сменит пользователь.

Когда мы забираем файл hello.c, клиент автоматически посылает команду TYPE I, чтобы установить тип файла в двоичный. На этот раз по соединению данных было передано 38 байт.

Требования к хостам Host Requirements RFC говорят, что FTP сервер должен поддерживать команду SYST (это было необязательным условием в RFC 959). Из систем описанных в тексте (см. внутреннюю сторону обложки) эту команду поддерживают BSD/386 и AIX 3.2.2. SunOS 4.1.3 и Solaris 2.x выдают на эту команду отклик 500 (команда неизвестна). SVR4 ведет себя совсем по-дикому: отвечает 500 и закрывает управляющее соединение!



Переменные в группе udp



Рисунок 25.8 Переменные в группе udp.

Мы будем использовать этот формат при описании всех переменных MIB в этой главе. Колонка, помеченная как "R/W", пуста, если переменная предназначена только для чтения или содержит точку (·), если переменную можно читать и записывать. Мы всегда будем включать эту колонку, даже если все переменные в группе только для чтения (как мы видели в группе udp), чтобы напомнить, что ни одна из переменных не может быть установлена менеджером. В случае если тип данных - INTEGER (целый) с ограничением, мы будем указывать верхний и нижний пределы, как сделано для номера порта UDP на следующем рисунке.

На рисунке 25.9 описываются две переменные в udpTable.

Таблица слушающего процесса (listener) UDP, index = <udpLocalAddress>.<udpLocalPort>
Имя Тип данных R/W Описание
udpLocalAddress IpAddress Локальный IP адрес слушающего процесса. 0.0.0.0 указывает, что слушающий процесс воспринимает датаграммы с любого интерфейса.
udpLocalPort [0..65535] Локальный номер порта слушающего процесса.


Переменные в таблице интерфейсов ifTable



Рисунок 25.18 Переменные в таблице интерфейсов: ifTable.

Мы можем запросить хост sun на предмет некоторых из этих переменных для всех его интерфейсов. Мы ожидаем увидеть три интерфейса (см. главу 3, раздел "Команда ifconfig"), если активизирован SLIP интерфейс:


sun % snmpi -a sun

snmpi> next ifTable во-первых, мы видим, чему равен индекс первого интерфейса
ifIndex.1=1

snmpi> get ifDescr.1 ifType.1 ifMtu.1 ifSpeed.1 ifPhysAddress.1
ifDescr.1="le0"
ifType.1=ethernet-csmacd (6)
ifMtu.1=1500
ifSpeed.1=10000000
ifPhysAddress.1=0x08:00:20:03:f6:42

snmpi> next ifDescr.1 ifType.1 ifMtu.1 ifSpeed.1 ifPhysAddress.1
ifDescr.2="sl0"
ifType.2=propPointToPointSerial (22)
ifMtu.2=552
ifSpeed.2=0
ifPhysAddress.2=0x00:00:00:00:00:00

snmpi> next ifDescr.2 ifType.2 ifMtu.2 ifSpeed.2 ifPhysAddress.2
ifDescr.3="lo0"
ifType.3=softwareLoopback (24)
ifMtu.3=1536
ifSpeed.3=0
ifPhysAddress.3=0x00:00:00:00:00:00

Во-первых, мы получили пять переменных для первого интерфейса, используя оператор get, а затем получили те же пять переменных для второго интерфейса, используя оператор get-next. Последняя команда получает эти же пять переменных для третьего интерфейса и опять с использованием команды get-next.

Тип интерфейса для SLIP канала сообщается как последовательное соединение точка-точка, а не SLIP. Также, не сообщается скорость SLIP канала.

Очень важно понять взаимосвязь между оператором get-next и порядком расположения информации в таблице, а именно колонка-строка. Когда мы задаем next ifDescr.1, возвращается следующая строка таблицы для этой переменной, а не следующую переменную в этой же строке. Однако если бы таблицы хранились в порядке строка-колонка, мы могли подобным образом перейти к следующему появлению заданной переменной.



Переменные в udpTable



Рисунок 25.9 Переменные в udpTable.

Каждый раз, когда мы описываем переменные в SNMP таблице, первая строка рисунка содержит значение "index", используемое для обращения к каждой строке таблицы. Мы покажем некоторые примеры того, как это делается, в следующем разделе.



Пересборка пакетов



Пересборка пакетов

Когда TCP отрабатывает тайм-ауты и осуществляет повторные передачи, он не должен повторно передавать идентичные сегменты (если исходно было 10 пакетов по одному байту, то при повторной передаче можно передать 1 пакет размером десять байт). Вместо этого, TCP разрешено осуществлять пересборку пакетов (repacketization), отправляя сегменты большего размера, что может увеличить производительность. (В действительности, сегменты большего размера не могут превосходить по размеру MSS, объявленный удаленным получателем.) Протокол TCP может себе это позволить, потому что он идентифицирует данные, которые были отправлены и подтверждены, по номерам байтов, а не по номерам сегментов.

Мы можем легко посмотреть, как это происходит. Воспользуемся программой sock, чтобы подсоединиться к discard серверу, и напечатаем одну строку. Затем мы отсоединяем Ethernet кабель и вводим вторую строку. Пока эта вторая строка будет повторно передаваться, мы вводим третью строку. При этом ожидается, что следующая повторная передача будет содержать обе и вторую, и третью строки.


bsdi % sock svr4 discard
hello there
первая строка отправлена нормально
отсоединяем Ethernet кабель
line number 2 эта строка будет повторно передаваться
and 3 вводим эту строку перед тем, как вторая отправлена нормально
подсоединяем обратно Ethernet кабель

На рисунке 21.13 показан вывод команды tcpdump. (Мы удалили установление соединения, прерывание соединения и все объявления окна.)


1 0.0 bsdi.1032 > svr4.discard: P 1:13(12) ack 1
2 0.140489 ( 0.1405) svr4.discard > bsdi.1032: . ack 13

здесь отсоединен Ethernet кабель

3 26.407696 (26.2672) bsdi.1032 > svr4.discard: P 13:27(14) ack 1
4 27.639390 ( 1.2317) bsdi.1032 > svr4.discard: P 13:27(14) ack 1
5 30.639453 ( 3.0001) bsdi.1032 > svr4.discard: P 13:27(14) ack 1

здесь напечатана третья строка

6 36.639653 ( 6.0002) bsdi.1032 > svr4.discard: P 13:33(20) ack 1
7 48.640131 (12.0005) bsdi.1032 > svr4.discard: P 13:33(20) ack 1
8 72.640768 (24.0006) bsdi.1032 > svr4.discard: P 13:33(20) ack 1

здесь Ethernet кабель подсоединен обратно

9 72.719091 ( 0.0783) svr4.discard > bsdi.1032: . ack 33



Пересборка пакетов TCP



Рисунок 21.13 Пересборка пакетов TCP.

В строках 1 и 2 показана первая строка ("hello there"), которая отправлена и подтверждена. Затем мы отсоединяем Ethernet кабель и печатаем "line number 2" (14 байт, включая символ новой строки). Эти байты передаются в строке 3, а затем повторно передаются в строках 4 и 5.

Перед тем как осуществляется повторная передача в строке 6, мы печатаем "and 3" (6 байт, включая символ новой строки) и видим, что повторная передача на этот раз содержит 20 байт: обе строки, которые мы напечатали. Подтверждение, которое прибывает в строке 9, подтверждает все 20 байт.



Пять операторов SNMP



Рисунок 25.1 Пять операторов SNMP.


Менеджер отправляет эти три запроса на UDP порт 161. Агент отправляет ловушки (trap) на UDP порт 162. Так как используются два разных порта, одна система может выступать в роли менеджера и агента одновременно. (См. упражнение 1 в конце главы.)

На рисунке 25.2 показан формат пяти SNMP сообщений, инкапсулированных в UDP датаграмму.



Показатели на маршрут



Показатели на маршрут

Более новые реализации TCP хранят большинство из показателей, которые мы описали в этой главе в записях таблицы маршрутизации. Предположим, что TCP соединение закрыто, при этом по соединению было отправлено достаточное количество данных, чтобы получить статистику, и запись в таблице маршрутизации для определенного пункта назначения не является маршрутом по умолчанию. При выполнении этих условий в записи таблицы маршрутизации сохраняется следующая информация (эта информация будет использована при следующих обращениях к этой записи): хэшированный RTT, хэшированное среднее отклонение и порог медленного старта. Понятие "достаточное количество данных" - означает 16 окон данных. При этом можно получить 16 примеров RTT, что позволяют фильтру хэшированного RTT получить значение с отклонением в пределах 5% от реального.

Помимо этого, администратор может воспользоваться командой route(8) , чтобы установить показатели для заданного маршрута: три показателя, упомянутых в предыдущем параграфе, а также MTU, емкость исходящего канала в зависимости от полосы пропускания (раздел "Пропускная способность для неинтерактивных данных" главы 20) и емкость входящего канала в зависимости от полосы пропускания.

Когда устанавливается новое TCP соединение, либо активное, либо пассивное, и пункт таблицы маршрутизации, который используется для этого соединения, имеет значения для этих показателей, соответствующие переменные инициализируются значениями показателей.



Полудуплексный символ за один раз строка за один раз или линейный режим (Linemode)?



Полудуплексный, символ за один раз, строка за один раз или линейный режим (Linemode)?

Существуют четыре режима, в которых функционирует большинство Telnet клиентов и серверов.

Полудуплексный.

Это режим по умолчанию, который, однако, редко используется в настоящее время. NVT по умолчанию это полудуплексное устройство, которое требует исполнения команды GO AHEAD (GA) от сервера, перед тем как будет принят ввод от пользователя. Ввод пользователя отображается локальным эхом от NVT клавиатуры на NVT принтер, таким образом, от клиента к серверу посылаются только полные строки.

Таким образом, обеспечивается минимальная поддержка терминала, однако подобным образом невозможно обеспечить полнодуплексную связь с хостами, которые поддерживают полнодуплексную форму общения, что является нормой на сегодняшний день. RFC 857 [Postel and Reynolds 1983c] определяет опцию ECHO (эхо), а RFC 858 [Postel and Reynolds 1983d] определяет опцию SUPPRESS GO AHEAD (запрещение команды go ahead). Комбинация этих двух опций предоставляет поддержку для следующего режима, символ за один раз, с удаленным эхом.

Символ за один раз.

Именно таким образом работает Rlogin. Каждый вводимый символ отправляется серверу отдельно от других. Сервер отражает эхом большинство символов, если только у приложения на сервере не отключено отражение эхом.

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

Для того чтобы сервер мог войти в этот режим, у него должна быть включена опция SUPPRESS GO AHEAD. Обсуждение этой опции осуществляется следующим образом: клиент посылает DO SUPPRESS GO AHEAD (требуя от сервера, чтобы тот включил опцию), или сервер посылает WILL SUPPRESS GO AHEAD клиенту (спрашивая о возможности включить эту опцию для самого себя). Затем сервер осуществляет WILL ECHO, спрашивая о возможности включить отражение эхом.

Строка за один раз.

Часто это называется "kludge line mode", потому что его реализация приходит от чтения между строк в RFC 858. Этот RFC декларирует, что должны присутствовать обе опции ECHO и SUPPRESS GO AHEAD, чтобы обеспечить ввод символа за один раз с удаленным эхом. Таким образом, если какая-либо из этих опций не включена, Telnet находится в режиме строка за один раз. В следующем разделе мы увидим пример того, как происходит обсуждение этого режима, и как он может быть отключен, когда программе сервера необходимо читать каждое нажатие клавиши. (То есть когда программа должна читать каждый символ, введенный пользователем, а не целую строку символов.)

Линейный режим (linemode).

В данном случае этот термин означает реальную опцию linemode, определенную в RFC 1184 [Borman 1990]. Эта опция обсуждается клиентом и сервером и корректирует все недостатки в режиме строка за один раз. Новые реализации поддерживают эту опцию.

На рисунке 26.11 показаны режимы функционирования по умолчанию между различными Telnet клиентами и серверами. Выражение "char" означает символ за один раз, "kludge" означает строка за один раз и "linemode" означает реальный линейный режим RFC 1184.

Клиент Сервер
SunOS 4.1.3 Solaris 2.2 SVR4 AIX 3.2.2 BSD/386 4.4BSD
SunOS 4.1.3 char char char char kludge kludge
Solaris 2.2 char char char char kludge kludge
SVR4 char char char char kludge kludge
AIX 3.2.2 char char char char kludge kludge
BSD/386 char char char char linemode linemode
4.4BSD char char char char linemode linemode


Попытки установить контакт с неработающим SMTP сервером



Рисунок 28.5 Попытки установить контакт с неработающим SMTP сервером.

В строке 1 vangogh отправляет SYN на порт 25 на первый IP адрес хоста sun: 140.252.1.29. В строке 2 мы видим отказ. SMTP клиент на vangogh пробует следующий IP адрес sun: 140.252.13.33 (строка 3), что также вызывает возврат RST (строка 4).

SMTP клиент не старается изменить свое поведение в результате ошибки, полученной на активное открытие, которое он осуществлял в строке 1, именно поэтому он старается обратиться к другому IP адресу в строке 2. Если ошибка была подобна "хост недоступен" (host unreachable) для первой попытки, возможно, что вторая попытка сработает.

Если причина, по которой активное открытие SMTP клиента не сработало, заключается в том, что хост выключен, мы увидим, что клиент будет повторно выдавать SYN на IP адрес 140.252.1.29 в течение 75 секунд (примерно так же, как на рисунке 18.6), затем отправит еще три SYN на IP адрес 140.252.13.33 в течение других 75 секунд. После 150 секунд клиент перейдет к следующей MX записи с более высоким значением предпочтительности.



Посылка почты на хост который использует MX записи



Рисунок 28.4 Посылка почты на хост, который использует MX записи.

В строке 1 MTA запрашивает свой DNS сервер о MX записи для mlfarm.com. Знак плюс, следующий за 2, означает, что установлен флаг "необходима рекурсия". Отклик в строке 2 имеет установленным бит полномочности (звездочка, следующая за 2) и содержит 2 записи ресурса (RR) ответа (два имени MX хостов), 0 записей ресурса RR прав доступа и две дополнительные RR (IP адреса двух хостов).

В строках 3-5 устанавливается TCP соединение с SMTP сервером на хосте mercury.hsi.com. Первоначальный отклик сервера (220) показан в строке 6.

Каким-либо образом хост mercury.hsi.com должен доставить это почтовое сообщение в пункт назначения - mlfarm.com. Протокол UUCP является распространенным способом обмена почтой с MX узлами для систем, которые не подключены к Internet.

В этом примере MTA запрашивает MX запись, получает ее и посылает почту. К сожалению, взаимодействие между MTA и DNS может отличаться в зависимости от реализации. RFC 974 указывает, что MTA должен сначала запросить MX записи, и если они не найдены, попробовать доставить почту на хост назначения (то есть запросить DNS на предмет записи A для хоста, его IP адрес). MTA должен также поинтересоваться записями CNAME в DNS (канонические имена).

Например, если мы пошлем почту хосту rstevens@mailhost.tuc.noao.edu с BSD/386 хоста, MTA (Sendmail) проделает следующее.

Sendmail запрашивает DNS, существуют ли записи CNAME для хоста mailhost.tuc.noao.edu. Мы видим, что записи CNAME существуют:

sun % host -t cname mailhost.tuc.noao.edu
mailhost.tuc.noao.edu CNAME noao.edu

Делается DNS запрос о существовании записи CNAME для noao.edu, в отклике сообщается, что записи не существует. Затем Sendmail запрашивает DNS о существовании MX записей для noao.edu и получает одну MX запись:

sun % host -t mx noao.edu
noao.edu MX noao.edu

Sendmail запрашивает DNS о существовании записей A (IP адрес) для noao.edu и получает значение 140.252.1.54. (Возможно, эта A запись была возвращена DNS сервером для noao.edu как дополнительная запись ресурса (RR) с MX откликом в шаге 3.) Открывается SMTP соединение на адрес 140.252.1.54, и почта отправляется.

Запрос CNAME не осуществляется для данных, возвращенных в MX записи (noao.edu). Данные в MX записи не могут быть псевдонимами - они должны быть именем хоста, который имеет запись A.

Версия Sendmail, распространяемая с SunOS.4.1.3, обращается к DNS только с запросами о существовании MX записей и сразу прекращает все попытки, если MX запись не найдена.



Поток данных от сервера к клиенту в примере Rlogin



Рисунок 26.6 Поток данных от сервера к клиенту в примере Rlogin.


Затемненная часть отправляющего буфера это неиспользуемая часть буфера размером в 4096 байт. На рисунке 26.7 приведена временная диаграмма для этого примера.

В сегментах 1-3 сервер отправляет клиенту сегменты полного размера. Подтверждение (ACK) в сегменте 4 всего лишь объявляет окно равное 1024, потому что вывод остановлен: так как клиент не может писать на терминал, он не может читать из сети. Сегмент 5 не полного размера, а ACK в сегменте 6 объявляет только оставшееся пространство в приемном буфере, размер премного буфера составляет 4096 байт. Клиент должен объявить окно размером 349 байт, потому что если он объявит окно равное 0 (как мы ожидаем, основываясь на алгоритме избежания "глупого окна", глава 22, раздел "Синдром "глупого" окна"), это приведет к тому, что правая граница окна сдвинется влево, что не должно произойти (глава 20, раздел "Изменение размера окна"). Так как сервер не может отправить буфер полного размера, когда он принимает сегмент 6, он прибегает к алгоритму предотвращения "глупого окна", не посылая ничего, при этом устанавливается устойчивый таймер (5 секунд). Когда таймер истекает, отправляется 349 байт (сегмент 7), и так как вывод клиента все еще остановлен, подтверждение в сегменте 8 объявляет окно равное 0.

В этот момент мы вводим символ прерывания, который передается в сегменте 9. Все еще объявлено окно равное 0. Когда Rlogin сервер получает символ прерывания, он передает его приложению (cat), и приложение прекращает свою работу. Так как приложение было остановлено вводом символа прерывания с терминала, его вывод сбрасывается и это передается серверу Rlogin. Это заставляет сервер посылать команду "очистить вывод" клиенту с использованием режима срочности TCP. Мы видим это в сегменте 10. Обратите внимание, что командный байт 0x02 имеет номер последовательности 30146 (указатель срочности минус один). Перед командным байтом находится 3419 байт (номера последовательности 26727:30145), они буферизированы сервером и сервер собирается их отправить.

Сегмент 10, с уведомлением срочности, содержит следующий байт данных, который передается от сервера клиенту (номер последовательности 26727). Он не содержит командный байт "очистить вывод". Сервер может послать этот единственный байт в сегменте 10 (глава 22, раздел "Пример"), так как отправитель всегда может проверить, закрыто ли окно, отправив 1 байт данных. TCP модуль клиента немедленно отвечает сегментом 11 с нулевым окном, однако прием уведомления о срочности в сегменте 10 заставляет TCP модуль клиента уведомить Rlogin клиента, что удаленный конец соединения вошел в режим срочности.



Представление данных



Представление данных

Протокол FTP предоставляет различные способы управления передачей и хранения файлов. Необходимо сделать выбор по четырем пунктам. Тип файла.

(а)

ASCII файлы.
(По умолчанию) Текстовый файл передается по соединению данных как NVT ASCII. При этом требуется, чтобы отправитель конвертировал локальный текстовый файл в NVT ASCII, а получатель конвертировал NVT ASCII в текстовый файл. Конец каждой строки передается в виде NVT ASCII символа возврата каретки, после чего следует перевод строки. Это означает, что получатель должен просматривать каждый байт в поисках пары символов CR, LF. (Мы видели тот же сценарий в случае передачи ASCII файла с помощью TFTP в разделе "Протокол" главы 15.)

(b)

EBCDIC файлы.
Альтернативный способ передачи текстовых файлов, когда на обоих концах системы EBCDIC.

(c)

Двоичные или бинарные файлы. (Image.)
Данные передаются как непрерывный поток битов.

(d)

Локальный тип файлов.
Способ передачи бинарных файлов между хостами, которые имеют различный размер байта. Количество битов в байте определяется отправителем. Для систем, которые используют 8-битные байты, локальный тип файла с размером байта равным 8 эквивалентен бинарному типу файла. Управление форматом. Применяется только для ASCII и EBCDIC файлов.

(a)

Nonprint. (По умолчанию)
Файл не содержит информацию вертикального формата.

(b)

Telnet format control.
Файл содержит управляющие символы вертикального формата Telnet, которые интерпретируются принтером.

(c)

Fortran carriage control.
Первый символ каждой строки это Fortran символ управления формата. Структура.

(a)

Структура файла.
(По умолчанию) Файл воспринимается в виде непрерывного потока байтов. Файл не имеет внутренней структуры.

(b)

Структура записи.
Эта структура используется только в случае текстовых файлов (ASCII или EBCDIC).

(c)

Структура страницы.
Каждая страница передается с номером страницы, что позволяет получателю хранить страницы в случайном порядке. Предоставляется операционной системой TOPS-20. (Требование к хостам Host Requirements RFC не рекомендует использовать эту структуру.) Режим передачи. Указывает на то, как файл передается по соединению данных.

(a)

Режим потока.
(По умолчанию) Файл передается как поток байтов. Для файловой структуры конец файла указывает на то, что отправитель закрывает соединение данных. Для структуры записи специальная 2-байтовая последовательность обозначает конец записи и конец файла.

(b)

Режим блоков.
Файл передается как последовательность блоков, перед каждым из них стоит один или несколько байт заголовков.

(c)

Сжатый режим.
Простое кодирование неоднократно встречающихся повторяющихся байт. В текстовых файлах обычно сжимаются пустые строки или строки из пробелов, а в бинарных строки из нулевых байт. (Этот режим поддерживается редко. Существуют более оптимальные способы сжатия файлов для FTP.)

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

Самые распространенные Unix реализации FTP клиента и сервера предоставляют следующий выбор: Тип: ASCII или двоичный. Управление форматом: только nonprint. Структура: только файловая структура. Режим передачи: только потоковый режим.

Это ограничивает нас одним из двух режимов: ASCII или двоичный.

Подобная реализация отвечает минимальным требованиям к хостам Host Requirements RFC. (RFC также требует обеспечить поддержку для структуры записи, однако только если операционная система поддерживает это, а Unix, как правило, не поддерживает.)

Большинство не-Unix реализаций предоставляет FTP возможности, которые позволяют обрабатывать их собственные форматы файлов. Требование к хостам Host Requirements RFC говорит: "Протокол FTP включает множество характеристик, некоторые из которых распространены не очень широко. Однако, для каждой характеристики в FTP существует по меньшей мере одна реализация."



Прекращение передачи файла сигнал синхронизации Telnet



Прекращение передачи файла: сигнал синхронизации Telnet

Сейчас мы посмотрим, как FTP клиент прекращает передачу файла от сервера. Прекратить передачу файла от клиента к серверу достаточно просто - клиент прекращает посылку данных по соединению данных и посылает ABOR на сервер по управляющему соединению. Прекращение приема, однако, более сложная задача, потому что клиент хочет, чтобы сервер немедленно прекратил передачу данных. Ранее мы упоминали, что для этого используется сигнал синхронизации Telnet.

Мы начали прием, после чего ввели символ прерывания. Ниже приведена интерактивная сессия, процесс идентификации пользователя удален:


ftp> get a.out получаем большой файл

---> TYPE I клиент и сервер - Unix системы с 8-битными байтами

200 Type set to I.

---> PORT 140,252,13,66,4,99
200 PORT command successful.

---> RETR a.out
150 Opening BINARY mode data connection for a.out (28672 bytes).

^? вводим символ прерывания
receive aborted вывод от клиента
waiting for remote to finish abort вывод от клиента

426 Transfer aborted. Data connection closed.
226 Abort successful

1536 bytes received in 1.7 seconds (0.89 Kbytes/s)

После того как введен символ прерывания, клиент немедленно сообщает, что он инициализировал прерывание передачи файла и ожидает, когда сервер его завершит. Сервер посылает два отклика: 426 и 226. Оба отклика посылаются Unix сервером, когда он принимает срочные данные от клиента с командой ABOR.

На рисунках 27.9 и 27.10 показаны временные диаграммы для этой сессии. Мы объединили вместе управляющее соединение (сплошные линии) и соединение данных (прерывистые линии), чтобы показать взаимосвязь между ними.



Прерывание от клиента



Прерывание от клиента

Проблема, напоминающая управление потоком данных, возникает, когда пользователь вводит символ прерывания (обычно DELETE или Control-C), чтобы прекратить процесс, запущенный на сервере. Сценарий подобен тому, который мы показали на рисунке 26.3. В этом случае также одно полное окно данных в канале между сервером и клиентом будет передано клиенту, до тех пор пока символ прерывания проделает свой путь по соединению в другом направлении. Мы хотим, чтобы символ прерывания остановил или прервал вывод данных на экран так быстро, как это возможно.

Достаточно редко поток данных от клиента к серверу может быть остановлен контролем потока данных. В этом направлении передаются только вводимые с клавитуры символы. Поэтому нет необходимости отправлять эти специальные символы (Control-S или прерывание) от клиента к серверу с использованием режима срочности TCP.



Прерывание передачи файла (первая половина)



Рисунок 27.9 Прерывание передачи файла (первая половина).


Первые 12 сегментов на рисунке 27.9 как раз такие, как мы ожидали. Команды и отклики по управляющему соединению настраивают системы на передачу файла, открывается соединение данных и от сервера к клиенту посылается первый сегмент данных.



Прерывание передачи файла (вторая половина)



Рисунок 27.10 Прерывание передачи файла (вторая половина).


Сегмент 13 на рисунке 27.10 - это квитанция на шестой сегмент данных от сервера по соединению данных. Затем следует сегмент 14, который сгенерирован нашим вводом символа прерывания. Для того чтобы прервать передачу, клиент посылает десять байт:

<IAC, IP, IAC, DM, A, B, O, R, \r, \n>

Мы видим два сегмента (14 и 15), это связано с проблемой определения положения указателя срочности TCP (подробно описанной в разделе "Режим срочности (Urgent Mode)" главы 20). (На рисунке 26.17 мы видели, как Telnet решает эту проблему.) Требование к хостам Host Requirements RFC говорит, что указатель срочности должен указывать на последний байт срочных данных, тогда как большинство Berkeley реализаций указывают на один байт позади последнего байта срочных данных. FTP клиент специально пишет первые 3 байта как срочные данные, зная, что указатель срочности будет (некорректно) указывать на следующий байт, который будет записан (метка данных, DM, с номером последовательности 54). Эта первая запись из 3 байт срочных данных посылается немедленно, вместе с указателем срочности, за ними следуют следующие 7 байт. (BSD FTP сервер не имеет проблемы с интерпретацией указателя срочности, который используется клиентом. Когда сервер принимает срочные данные по управляющему соединению, он читает следующую FTP команду, в поиске ABOR или STAT, игнорируя любые вложенные команды Telnet.)

Несмотря на то, что сервер сообщил о прекращении передачи (сегмент 18, по управляющему соединению), клиент получил еще 14 сегментов данных (номера последовательности 1537 - 5120) по соединению данных. Эти сегменты, скорее всего, были поставлены в очередь в драйвере сетевого устройства на сервере, когда был принят сигнал о прекращении передачи. Однако клиент печатает "1536 байт принято", а это означает, что он проигнорировал эти сегменты данных (сегменты 17 и позже), которые были приняты после отправки прерывания передачи (сегменты 14 и 15).

В случае Telnet, когда пользователь вводит символ прерывания (рисунок 26.17), Unix клиент по умолчанию не посылает команду прерывания процесса в виде срочных данных. В этом нет ничего страшного, потому что существует очень маленькая вероятность того, что поток данных от клиента к серверу остановлен управлением потока данных. В случае FTP клиент также посылает команду прерывания процесса по управляющему соединению, и так как используется два соединения, существует очень небольшая вероятность того, что управляющее соединение будет остановлено управлением потока данных. Почему FTP посылает команду прерывания процесса в виде срочных данных, тогда как Telnet не делает этого? Дело в том, что FTP использует два соединения, тогда как Telnet использует одно, а для некоторых операционных систем довольно сложно обработать информацию приходящую по двум соединениям одновременно. FTP подразумевает, что эти операционные системы по крайней мере смогут понять, что по управляющему соединению срочные прибыли данные, и что в свою очередь позволит серверу переключиться от обработки соединения данных на обработку управляющего соединения.



Мы можем посмотреть, как ICMP



Пример

Мы можем посмотреть, как ICMP ошибка о недоступности хоста обрабатывается на нашем SLIP канале, когда он погашен в середине соединения. Мы установили соединение с хоста slip на хост aix. (На рисунке, находящемся на внутренней стороне обложки, мы видим, что это соединение проходит через SLIP канал.) После установления соединения и передачи какого-то количества данных, SLIP канал между маршрутизаторами sun и netb погашен. При этом запись, соответствующая маршруту по умолчанию в sun (которую мы показывали на рисунке 9.2), будет удалена. Ожидается, что sun затем будет отвечать на IP датаграммы, направляемые в Ethernet сеть 140.252.1, ошибкой ICMP о недоступности хоста. Мы хотим посмотреть, как TCP обрабатывает эти ICMP ошибки.
Здесь приведена интерактивная сессия на хосте slip:

slip % sock aix echo запускаем программу sock
test line вводим эту строку
test line она отображается эхом
в этом месте SLIP канал выключен
another line затем вводим эту строку и смотрим повторные передачи
здесь SLIP канал восстановлен
another line и происходит обмен строкой и ее эхом
line number 3
line number 3
the last line
SLIP канал погашен и не восстановлен
read error: No route to host TCP в конце концов закрывает соединение

На рисунке 21.12 показан соответствующий вывод команды tcpdump, полученный на маршрутизаторе bsdi. (Установление соединения и все объявления окна удалены.) Мы подсоединились к эхо серверу на хосте aix и напечатали "test line" (строка 1). Она отразилась эхом (строка 2), и эхо было подтверждено (строка 3). Затем мы погасили SLIP канал.
Затем ввели "another line" (строка 3) и ожидаем, что TCP отработает тайм-аут и повторно передаст сообщение. И действительно, эта строка отправляется шесть раз перед тем, как будет получен отклик. Строки 4-13 показывают первую передачу и следующие четыре повторные передачи, каждая из которых генерирует ICMP ошибку о недоступности хоста с маршрутизатора sun. Это как раз то, что мы ожидали: IP датаграммы, двигаются от slip к маршрутизатору bsdi (который имеет маршрут по умолчанию, указывающий на sun) и затем на sun, где и находится поврежденный канал.
Пока происходят эти повторные передачи, SLIP канал восстанавливается, и повторная передача в строке 14 достигают пункта назначения. Строка 15 это эхо от aix, а строка 16 - подтверждение на эхо.
Можно сделать вывод, что TCP игнорирует ICMP ошибку о недоступностии хоста и продолжает осуществлять повторные передачи. Мы также видим ожидаемое экспотенциальное наращивание времени в каждом тайм-ауте при повторной передаче: первый возникает через 2,5 секунды, затем умножается на 2 (при этом длительность тайм-аута составляет 5 секунд), затем на 4 (10 секунд), затем на 8 (20 секунд) и затем на 16 (40 секунд).
После чего мы напечатали третью строку ввода ("line number 3") и увидели, что она отправлена в строке 17, отражена эхом в строке 18, и эхо подтверждено в строке 19.
Сейчас мы хотим посмотреть, что произойдет, когда TCP осуществляет повторную передачу, а затем прекращает попытки после получения ICMP ошибки о недоступности хоста. Для этого мы снова выключаем SLIP канал. После того как канал выключен, мы печатаем "the last line" и видим, что она передается 13 раз перед тем, как TCP прекращает попытки. (Строки 30-43 удалены из вывода. В них показаны дополнительные повторные передачи.)
Необходимо обратить внимание на одну деталь которая, заключается в том, что сообщение об ошибке печатается нашей программой sock, когда она в конце концов прекращает работу: "No route to host". (Нет маршрута к хосту.) Это соответствует ошибке операцинной системы Unix, которая, в свою очередь соответствует ICMP ошибке о недоступности хоста (рисунок 6.12). Значит, TCP сохраняет ICMP ошибку, которую он получил по соединению, и когда он в конце концов прекращает свою работу, то печатает эту ошибку вместо "Connection timed out" (соединение закрыто по тайм-ауту).
И в заключение, обратите внимание на то, что временные промежутки между повторными передачами в строках 22-46 сравнимы с промежутками в строках 6-14. Это происходит из-за того, что TCP обновил свои оценочные функции, когда третья строка, которую мы напечатали, была отправлена и подтверждена без повторных передач в строках 17-19. Исходный тайм-аут повторной передачи в настоящее время равен 3 секундам, при этом последующие значения будут равны 6, 12, 24, 48 и затем верхний предел 64.

1 0.0 slip.1035 > aix.echo: P 1:11(10) ack 1
2 0.212271 ( 0.2123) aix.echo > slip.1035: P 1:11(10) ack 11
3 0.310685 ( 0.0984) slip.1035 > aix.echo: . ack 11

здесь SLIP канал выключен

4 174.758100 (174.4474) slip.1035 > aix.echo: P 11:24(13) ack 11
5 174.759017 ( 0.0009) sun > slip: icmp: host aix unreachable

6 177.150439 ( 2.3914) slip.1035 > aix.echo: P 11:24(13) ack 11
7 177.151271 ( 0.0008) sun > slip: icmp: host aix unreachable

8 182.150200 ( 4.9989) slip.1035 > aix.echo: P 11:24(13) ack 11
9 182.151189 ( 0.0010) sun > slip: icmp: host aix unreachable

10 192.149671 ( 9.9985) slip.1035 > aix.echo: P 11:24(13) ack 11
11 192.150608 ( 0.0009) sun > slip: icmp: host aix unreachable

12 212.148783 ( 19.9982) slip.1035 > aix.echo: P 11:24(13) ack 11
13 212.149786 ( 0.0010) sun > slip: icmp: host aix unreachable

здесь SLIP канал включен

14 252.146774 ( 39.9970) slip.1035 > aix.echo: P 11:24(13) ack 11
15 252.439257 ( 0.2925) aix.echo > slip.1035: P 11:24(13) ack 24
16 252.505331 ( 0.0661) slip.1035 > aix.echo: . ack 24

17 261.977246 ( 9.4719) slip.1035 > aix.echo: P 24:38(14) ack 24
18 262.158758 ( 0.1815) aix.echo > slip.1035: P 24:38(14) ack 38
19 262.305086 ( 0.1463) slip.1035 > aix.echo: . ack 38

здесь SLIP канал выключен

20 458.155330 (195.8502) slip.1035 > aix.echo: P 38:52(14) ack 38
21 458.156163 ( 0.0008) sun > slip: icmp: host aix unreachable

22 461.136904 ( 2.9807) slip.1035 > aix.echo: P 38:52(14) ack 38
23 461.137826 ( 0.0009) sun > slip: icmp: host aix unreachable

24 467.136461 ( 5.9986) slip.1035 > aix.echo: P 38:52(14) ack 38
25 467.137385 ( 0.0009) sun > slip: icmp: host aix unreachable

26 479.135811 ( 11.9984) slip.1035 > aix.echo: P 38:52(14) ack 38
27 479.136647 ( 0.0008) sun > slip: icmp: host aix unreachable

28 503.134816 ( 23.9982) slip.1035 > aix.echo: P 38:52(14) ack 38
29 503.135740 ( 0.0009) sun > slip: icmp: host aix unreachable

здесь удалено 14 строк вывода

44 1000.219573 ( 64.0959) slip.1035 > aix.echo: P 38:52(14) ack 38
45 1000.220503 ( 0.0009) sun > slip: icmp: host aix unreachable

46 1064.201281 ( 63.9808) slip.1035 > aix.echo: R 52:52(0) ack 38
47 1064.202182 ( 0.0009) sun > slip: icmp: host aix unreachable

Пример идентификации строк в таблице слушающего процесса UDP



Рисунок 25.12 Пример идентификации строк в таблице слушающего процесса UDP.

Колонка Идентификатор объекта (в лексикографическом порядке) Сокращенное имя Значение
1 1.3.6.1.2.1.7.5.1.1.0.0.0.0.67
1.3.6.1.2.1.7.5.1.1.0.0.0.0.161
1.3.6.1.2.1.7.5.1.1.0.0.0.0.520
udpLocalAddress.0.0.0.0.67
udpLocalAddress.0.0.0.0.161
udpLocalAddress.0.0.0.0.520
0.0.0.0
0.0.0.0
0.0.0.0
2 1.3.6.1.2.1.7.5.1.2.0.0.0.0.67
1.3.6.1.2.1.7.5.1.2.0.0.0.0.161
1.3.6.1.2.1.7.5.1.2.0.0.0.0.520
udpLocalPort.0.0.0.0.67
udpLocalPort.0.0.0.0.161
udpLocalPort.0.0.0.0.520
67
161
520








Пример MIME сообщения состоящего из нескольких частей



Рисунок 28.8 Пример MIME сообщения, состоящего из нескольких частей.

Этот раздел является кратким описанием MIME. Для получения более подробной информации и примеров MIME можно обратиться к RFC 1521 и [Rose 1993].



Пример опции масштабирования окна



Рисунок 24.7 Пример опции масштабирования окна.

В строке 1 vangogh объявляет окно размером 65535 и указывает опцию масштабирования окна со сдвиговым счетчиком равным 1. Это объявленное окно имеет максимально возможное значение, однако оно меньше чем размер приемного буфера (128000), потому что поле окна в сегменте SYN никогда не масштабируется.

Коэффициент масштабирования равный 1 означает, что vangogh хочет объявить окна размером до 131070 (65535 x 21). Это соотносимо с размером приемного буфера (128000). Так как bsdi не отправлял опцию масштабирования окна в своем SYN (строка 2), эта опция не используется. Обратите внимание на то, что vangogh и дальше продолжает использовать максимально возможный размер окна (65535) для соединения.

Для второго соединения vangogh устанавливает сдвиговый счетчик в значение 2, а это означает, что он собирается отправить объявления окна размером до 262140 (65535 x 22), то есть больше чем размер приемного буфера (220000).



Пример "оставайся в живых" когда удаленный хост вышел из строя и перезагрузился



Рисунок 23.2 Пример "оставайся в живых", когда удаленный хост вышел из строя и перезагрузился.

Мы установили соединение и послали 9 байт данных от клиента к серверу (строки 1-3). Два часа спустя клиент отправил первую пробу "оставайся в живых", отклик от сервера содержит сброс. Приложение клиента печатает сообщение об ошибке "Connection reset by peer" (соединение сброшено удаленным концом).



Пример "оставайся в живых" когда удаленный конец недоступен



Рисунок 23.3 Пример "оставайся в живых", когда удаленный конец недоступен.

Мы начинаем этот пример так же, как и предыдущий: в строках 1-3 убеждаемся, что соединение функционирует. На первую пробу "оставайся в живых", отправляемую через 2 часа, успешно получен отклик (строки 4 и 5), однако перед тем, как будет отправлена следующая, еще через 2 часа, мы выключили SLIP соединение между маршрутизаторами sun и netb. (Обратитесь к топологии, приведенной на внутренней стороне обложки.)

На пробу "оставайся в живых" в строке 6 генерируется ICMP ошибка о недоступности сети от маршрутизатора sun. Как мы описали в разделе "ICMP ошибки" главы 21, это всего лишь "мягкая" ошибка для принимающего TCP на хосте slip. Он фиксирует, что была принята ICMP ошибка, однако получение ошибки не разрывает соединение. Отправляются еще 9 проб "оставайся в живых", с интервалом в 75 секунд, перед тем, как хост прекращает свои попытки. Ошибка, возвращаемая приложению, генерирует другое сообщение: "No route to host" (нет маршрута к хосту). На рисунке 6.12 мы видели, что это соответствует ICMP ошибке о недоступности сети.



Пример переполнения



Пример переполнения

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

В начале раздела "Пример RTT" этой главы мы сказали, что полное время передачи составляло примерно 45 секунд, однако на этом рисунке мы показали только 35 секунд. (Потому что, именно 35 секунд потребовалось для передачи только сегментов данных.) Первый сегмент данных не передавался в течении 6,3 секунды после отправки первого SYN, потому что первый SYN был потерян при передаче и передан повторно (рисунок 21.5). После того как последний сегмент данных и FIN были отправлены (момент времени 34,1 на рисунке 21.6), потребовалось еще примерно 4,0 секунды на то, чтобы принять последние 14 ACK от получателя перед тем, как от получателя был получен FIN.



Пример переполнения (продолжение)



Пример переполнения (продолжение)

Просматривая соединение с использованием tcpdump и отладочной опции сокетов (которую мы описали в разделе "Пример RTT"), мы можем увидеть значения cwnd и ssthresh при передаче каждого сегмента. Если максимальный размер сегмента (MSS) равен 256 байт, исходные значения cwnd и ssthresh будут равны 256 и 65535 соответственно. Каждый раз, когда принимается ACK, cwnd увеличивается на значение MSS и принимает значения 512, 768, 1024, 1280 и так далее. Предположим, что переполнения не происходит, поэтому окно переполнения достигнет значения окна, объявленного получателем, а это, в свою очередь, будет означать, что объявленное окно ограничивает поток данных.

Однако нам интересно посмотреть, что произойдет в случае возникновения переполнения. Рассмотрим тот же пример из раздела "Пример RTT". В этом примере переполнение появлялось четыре раза. Был тайм-аут при передаче исходного SYN, который предназначался для установления соединения (рисунок 21.5), после чего, в процессе передачи данных, было потеряно три пакета (рисунок 21.6).

На рисунке 21.9 показаны значения двух переменных cwnd и ssthresh, когда осуществлялась повторная передача исходного SYN, за которым следовало семь первых сегментов данных. (Мы показали обмен исходными сегментами данных и их ACK на рисунке 21.2.) Переданные байты данных показаны в формате вывода команды tcpdump: 1:257(256), что означает байты с 1 по 256.

Когда возникает тайм-аут при передаче SYN, ssthresh устанавливается в свое минимальное значение (512 байт, что равно, в этом примере, двум сегментам). cwnd устанавливается в один сегмент (256 байт), чтобы войти в фазу медленного старта.

Когда получены SYN и ACK, с этими переменными ничего не происходит, так как новые данные не были подтверждены.

Когда прибывает ACK 257, мы все еще находимся в режиме медленного старта, так как cwnd меньше либо равно ssthresh, поэтому cwnd увеличивается на 256. То же самое происходит, когда прибывает ACK 513.

Когда прибывает ACK 769, мы больше не находимся в режиме медленного старта, однако переходим в режим предотвращения переполнения. Новое значение cwnd рассчитывается следующим образом

cwnd ¬ cwnd + (разм.сегмента x разм.сегмента)/cwnd + разм.сегмента/8

Это больше на 1/cwnd, чем то, что мы показали ранее, принимая во внимание то, что cwnd рассчитывается в действительности в байтах, а не в сегментах. Для этого примера мы рассчитаем

cwnd ¬ 768 + (256 x 256)/768 + 256/8

Номер сегмента (рисунок 21.2) Действие Переменная
Отправлено Получено Комментарий cwnd ssthresh
инициализация 256 65535
SYN

SYN

тайм-аут

повторная передача

256 512
SYN, ACK
ACK
1 1:257(256)
2 ACK 257 медленный старт 512 512
3 257:513(256)
4 513:769(256)
5 ACK 513 медленный старт 768 512
6 769:1025(256)
7 1025:1281(256)
8 ACK 769 предотвращение переполнения 885 512
9 1281:1537(256)
10 ACK 1025 предотвращение переполнения 991 512
11 1537:1793(256)
12 ACK 1281 предотвращение переполнения 1089 512


Пример предотвращения переполнения



Рисунок 21.9 Пример предотвращения переполнения.

что равно 885 (с использованием целочисленной арифметики). Когда прибывает следующий ACK 1025, мы рассчитаем

cwnd ¬ 885 + (256 x 256)/885 + 256/8

что равно 991.

Это суммарное увеличение cwnd продолжается до появления первой повторной передачи, которая происходит в районе 10-секундной метки на рисунке 21.6. Рисунок 21.10 это график для тех же самых данных, которые приведены на рисунке 21.6, но сюда добавлены значения cwnd.

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

Нам необходимо объяснить, что происходит в трех точках, когда возникает повторная передача. Вспомним, что каждая повторная передача возникает из-за того, что были приняты три дублированных ACK (это указывает на то, что пакет был потерян). Здесь вступает в действие алгоритм быстрой повторной передачи, описанный в разделе "Быстрая повторная передача и алгоритм быстрого восстановления". ssthresh сразу же устанавливается в половину размера окна, который соответствовал тому моменту, когда была осуществлена повторная передача, однако cwnd позволяет продолжать увеличение до тех пор, пока принимаются дублированные ACK, так как каждый дублированный ACK означает, что сегмент все еще находится в сети (принимающий TCP буферизировал его, ожидая прибытия отсутствующих данных).



Рисунок 21.11 Пример предотвращения переполнения (продолжение).

Значения cwnd увеличиваются постоянно, от последнего значения на рисунке 21.9 для сегмента 12 (1089), до первого значения на рисунке 21.11 для сегмента 58 (2426). Значение ssthresh осталось тем же самым (512), так как за этот период не было осуществлено повторных передач.

Когда прибыли первые два дублированные ACK (сегменты 60 и 61), они просто подсчитываются (третий дублированный ACK не прибыл), а cwnd остается неизменным. (Эта неизменяющаяся часть рисунка 21.10, предваряет первую повторную передачу.) Однако когда прибывает третий ACK, ssthresh устанавливается в значение равное половине cwnd. cwnd устанавливается в значение ssthresh плюс размер сегмента, умноженный на количество дублированных ACK (1024 + 3 x 256). Затем осуществляется повторная передача.

Прибывает еще пять дублированных ACK (сегменты 64-66, 68 и 70), при этом cwnd каждый раз увеличивается на размер сегмента. Наконец, прибывает новый ACK (сегмент 72), и cwnd устанавливается в значение ssthresh (1024), при этом стартует стандартный алгоритм предотвращения переполнения. Так как cwnd меньше или равно ssthresh (они равны), к cwnd добавляется размер сегмента, при этом получается значение 1280. Когда прибывает следующий ACK (который не показан на рисунке 21.11), cwnd больше чем ssthresh, поэтому cwnd устанавливается в значение 1363.

В течение фазы быстрой повторной передачи и быстрого восстановления мы передаем новые данные после получения дублированных ACK в сегментах 66, 68 и 70, однако не после получения дублированных ACK в сегментах 64 и 65. Причина этого заключается в значении cwnd по сравнению с количеством неподтвержденных байтов данных. Когда прибывает сегмент 64, cwnd становится равным 2048, однако мы имеем 2304 неподтвержденных байта (девять сегментов: 46, 48, 50, 52, 54, 55, 57, 59 и 63). Мы ничего не можем послать. Когда прибывает сегмент 65, cwnd становится равным 2304, поэтому мы все еще ничего не можем отправить. Однако, когда прибывает сегмент 66, cwnd становится равным 2560, теперь мы можем послать новый сегмент данных. Точно так же, когда прибывает сегмент 68, cwnd становится равным 2816, что больше чем 2560 байт неподтвержденных данных, таким образом, мы можем послать еще один новый сегмент данных. То же самое происходит, когда прибывает сегмент 70.

Когда в момент времени 14,3 происходит следующая повторная передача (см. рисунок 21.10), которая также вызвана приемом трех дублированных ACK, мы видим такое же увеличение cwnd как если бы прибыл еще один дублированный ACK, после чего происходит уменьшение до 1024.

Повторная передача в момент времени 21,1 на рисунке 21.10 также происходит при приходе дублированных ACK. Мы получили еще три дублированных ACK после повторной передачи, поэтому мы видим три дополнительных увеличения cwnd, после чего следует уменьшение до 1280. Для остальной передачи cwnd увеличивается линейно с окончательным значением 3615.



Пример Rlogin когда клиент останавливает вывод и затем прерывает работу программы на сервере



Рисунок 26.7 Пример Rlogin, когда клиент останавливает вывод и затем прерывает работу программы на сервере.


Как только Rlogin клиент получает уведомление о срочности от своего TCP, он начинает считывание данных, которые уже ожидают этого, окно открывается (сегмент 13). Данные, буферизированные сервером, отправляются (сегменты 14, 15, 17 и 18). Последний сегмент содержит последний байт срочных данных (номер последовательности 30146), который содержит командный байт, передаваемый от сервера клиенту. Когда клиент считывает этот байт, он отбрасывает все данные, которые он прочитал в сегментах 14, 15, 17 и 18, и очищает свою выходную очередь на терминал. Следующие 2 байта в сегменте 19 содержат эхо символа прерывания: "^?". Последний сегмент, который мы показали (21), содержит приглашение shellа от клиента.

Этот пример показывает, как данные могут быть буферизированы на обоих концах соединения, когда клиент вводит символ прерывания. Если сброшено будет только 3419 байт, буферизированных на сервере, при этом 4096 байт у клиента сброшено не будет, эти 4096 байт данных вместе с тем, что было буферизировано в выходной очереди терминала у клиента, появятся в выводе.



Пример RTT



Пример RTT

В этой главе мы рассмотрим примеры, которые проиллюстрируют детали разных реализаций TCP тайм-аутов и повторных передач, медленный старт и предотвращение переполнения.

С помощью программы sock отправлено 32768 байт данных с хоста slip на discard сервис хоста vangogh.cs.berkeley.edu:

slip % sock -D -i -n32 vangogh.cs.berkeley.edu discard

Обратимся к рисунку, находящемуся на внутренней стороне обложки. Из рисунка видно, что slip подсоединен к Ethernet 140.252.1 двумя SLIP каналами, а затем через Internet к пункту назначения. Так как используется два SLIP канала (со скоростью 9600 бит в секунду), мы ожидаем появления определенных задержек.

Команда, приведенная выше, осуществит 32 записи по 1024 байта. Так как MTU между slip и bsdi составляет 296, то будет сгенерировано 128 сегментов, каждый из которых будет содержать 256 байт пользовательских данных. Полное время передачи займет примерно 45 секунд, и мы увидим один тайм-аут и три повторные передачи.

Пока осуществляется эта передача, мы запустим tcpdump на хосте slip, чтобы увидеть все сегменты, которые были переданы и приняты. В дополнение мы указали опцию -D, чтобы включить отладку сокетов (см. приложение A, раздел "Опция отладки сокета"). Кроме того, у нас была возможность запустить модифицированную версию программы trpt(8), которая позволяет напечатать некоторые переменные в блоке управления соединением, имеющие отношение к временам задержки, медленному старту и предотвращению переполнения.

Из-за того, что вывод достаточно большой, мы не можем показать его целиком, однако рассмотрим его по частям, в процессе изучения главы. На рисунке 21.2 показана передача данных и подтверждений в течение первых 5 секунд. Мы немного модифицировали этот вывод от предыдущего вывода команды tcpdump. Мы только оценили моменты времени, когда пакет отправлялся или принимался хостом, на котором запущена программа tcpdump, на этом рисунке мы хотели показать, что пакет двигается по сети (так как это соединение в локальной сети не похоже на распределенный Ethernet), и показать, когда принимающий хост, возможно, генерирует подтверждения. (Мы удалили все объявления окна. slip всегда объявляет окно размером 4096, а vangogh всегда объявляет окно 8192.)



Пример соединения данных FTP



Рисунок 27.7 Пример соединения данных FTP.












Пример таблицы at (ARP кэш)



Рисунок 25.20 Пример таблицы at (ARP кэш).

Физические адреса AppleTalk с номером интерфейса - 2 имеют 32-битные значения, а не 48-битные, как у привычных Ethernet адресов. Также обратите внимание на то, что существуют запись для нашего маршрутизатора (netb находится по адресу 140.252.1.183), так как kinetics и netb находятся на одном и том же Ethernet кабеле (140.252.1), и kinetics должен использовать ARP, чтобы послать нам SNMP отклик.



Пример управляющего соединения FTP



Рисунок 27.6 Пример управляющего соединения FTP.












Пример устойчивого таймера при пробах окна нулевого размера



Рисунок 22.1 Пример устойчивого таймера при пробах окна нулевого размера.

В сегментах 1-13 осуществляется обычная передача данных от клиента к серверу, при этом заполняется окно размером 9216 байт. Сервер объявил окно равное 4096 и имеет размер буфера сокета по умолчанию равный 4096, однако в действительности принимает 9216 байт. Это является формой взаимодействия между кодами TCP/IP и потоковой подсистемой в SVR4.

В сегменте 13 сервер подтверждает предыдущие четыре сегмента данных, однако объявляет окно равное 0, приостанавливая тем самым передачу данных от клиента. Клиент вынужден установить свой устойчивый таймер. Если клиент не получил обновление окна до истечения таймера, он осуществляет пробу пустого окно, чтобы проверить не было ли потеряно обновление окна. Так как процесс сервера спит, 9216 байт данных буферизированы TCP и ожидают, что будут переданы приложению.

Обратите внимание на промежутки времени между пробами окна, которые осуществляет клиент. Первая (сегмент 14) происходит через 4,949 секунды после получения окна нулевого размера. Следующая (сегмент 16) - через 4,996 секунды. Затем промежутки между пробами становятся приблизительно равными 6, 12, 24, 48 и 60 секунд после предыдущей пробы.

Почему промежутки всегда на какую-то долю секунды меньше чем 5, 6, 12, 24, 48 и 60? Пробы осуществляются в соответствии с 500-миллисекундным таймером TCP. Когда таймер истекает, отправляется проба окна, а отклик принимается примерно через 4 миллисекунды. Получение отклика, вновь устанавливает таймер, однако время до следующего тика часов составляет примерно 500 минус 4 миллисекунды.

При расчете устойчивого таймера используется обычное экспотенциальное наращивание TCP. Первый тайм-аут рассчитывается как 1,5 секунды для стандартного соединения по локальной сети. Затем это значение умножается на 2 для второго тайм-аута (значение равное 3 секундам). Множитель равный 4-м дает следующее значение равное 6, множитель равный 8-ми дает значение 12, и так далее. Однако, устойчивый таймер всегда находится в диапазоне между 5 и 60 секундами, и именно эти значения мы видим на рисунке 22.1.

Проба окна содержит 1 байт данных (номер последовательности 9217). TCP всегда позволяет послать 1 байт данных, после того как окно было закрыто. Однако подтверждения, возвращающиеся с номером окна равным 0, не подтверждают этот байт. (Эти ACK получены для всех байтов с номером меньше чем 9216, и на байт с номером 9216.) Поэтому, этот байт будет передан повторно.

Характеристика устойчивого состояния отличается от тайм-аутов при повторной передаче, описанных в главе 21, тем, что TCP никогда не прекращает отправку проб окна. Эти пробы окна отправляются с 60-секундными интервалами до тех пор, пока окно не будет открыто, или приложение решит, что соединение должно быть разорвано.



Пример выход сервера из строя



Пример: выход сервера из строя

В следующем примере мы читаем файл с NFS сервера, когда сервер выходит из строя и перезагружается. Это покажет как "безразличность" сервера позволяет, клиенту "не знать" о том, что сервер вышел из строя. Все то время, пока сервер сломался и перезагружается, клиент не знает о проблеме, и приложение клиента работает так же, как и раньше.

На клиенте sun мы стартовали cat с очень большим файлом в качестве аргумента (/usr/share/lib/termcap на NFS сервере svr4), отсоединили Ethernet кабель в процессе передачи, выключили и перезагрузили сервер и затем снова подсоединили кабель. Клиент был сконфигурирован таким образом, чтобы читать 1024 байта за одно NFS чтение. На рисунке 29.9 показан вывод tcpdump.

Строки 1-10 соответствуют открытию файла клиентом. Эта операция напоминает ту, что показана на рисунке 29.7. В строке 11 мы видим первое чтение (READ) из файла 1024-х байт данных; отклик возвратился в строке 12. Это продолжается до строки 129 (чтение READ по 1024 байта и затем отклик OK).

В строках 130 и 131 мы видим два запроса, которые отработаны по тайм-ауту и повторно переданы в строках 132 и 133. Первый вопрос: мы видим два запроса на чтение, один начинается со смещения 65536, а другой начинается со смещения 73728, почему? Ядро клиента определило, что приложение клиента осуществляет последовательное считывание, и постаралось получить блоки данных заранее. (Большинство Unix ядер осуществляют это чтение вперед (read-ahead).) Ядро клиента также запустило несколько NFS демонов блочного ввода-вывода (I/O) (biod процессы), которые стараются сгенерировать несколько RPC запросов от имени клиента. Один демон считывает 8192 байта, начиная с 65536 (в 1024-байтных цепочках), а другие осуществляют чтение вперед по 8192 байта, начиная с 73728.

Повторные передачи клиента появляются в строках 130-168. В строке 169 мы видим, что сервер перезагрузился, и послал ARP запрос перед тем, как откликнуться на NFS запрос клиента из строки 168. Отклик на строку 168 посылается в строке 171. Запросы клиента на чтение (READ) продолжаются.


1 0.0 sun.7ade > svr4.nfs: 104 getattr
2 0.007653 ( 0.0077) svr4.nfs > sun.7ade: reply ok 96

3 0.009041 ( 0.0014) sun.7adf > svr4.nfs: 116 lookup "share"
4 0.017237 ( 0.0082) svr4.nfs > sun.7adf: reply ok 128

5 0.018518 ( 0.0013) sun.7ae0 > svr4.nfs: 112 lookup "lib"
6 0.026802 ( 0.0083) svr4.nfs > sun.7ae0: reply ok 128

7 0.028096 ( 0.0013) sun.7ae1 > svr4.nfs: 116 lookup "termcap"
8 0.036434 ( 0.0083) svr4.nfs > sun.7ae1: reply ok 128

9 0.038060 ( 0.0016) sun.7ae2 > svr4.nfs: 104 getattr
10 0.045821 ( 0.0078) svr4.nfs > sun.7ae2: reply ok 96

11 0.050984 ( 0.0052) sun.7ae3 > svr4.nfs: 116 read 1024 bytes @ 0
12 0.084995 ( 0.0340) svr4.nfs > sun.7ae3: reply ok 1124

считывание

128 3.430313 ( 0.0013) sun.7b22 > svr4.nfs: 116 read 1024 bytes @ 64512
129 3.441828 ( 0.0115) svr4.nfs > sun.7b22: reply ok 1124

130 4.125031 ( 0.6832) sun.7b23 > svr4.nfs: 116 read 1024 bytes @ 65536
131 4.868593 ( 0.7436) sun.7b24 > svr4.nfs: 116 read 1024 bytes @ 73728

132 4.993021 ( 0.1244) sun.7b23 > svr4.nfs: 116 read 1024 bytes @ 65536
133 5.732217 ( 0.7392) sun.7b24 > svr4.nfs: 116 read 1024 bytes @ 73728

134 6.732084 ( 0.9999) sun.7b23 > svr4.nfs: 116 read 1024 bytes @ 65536
135 7.472098 ( 0.7400) sun.7b24 > svr4.nfs: 116 read 1024 bytes @ 73728

136 10.211964 ( 2.7399) sun.7b23 > svr4.nfs: 116 read 1024 bytes @ 65536
137 10.951960 ( 0.7400) sun.7b24 > svr4.nfs: 116 read 1024 bytes @ 73728

138 17.171767 ( 6.2198) sun.7b23 > svr4.nfs: 116 read 1024 bytes @ 65536
139 17.911762 ( 0.7400) sun.7b24 > svr4.nfs: 116 read 1024 bytes @ 73728

140 31.092136 (13.1804) sun.7b23 > svr4.nfs: 116 read 1024 bytes @ 65536
141 31.831432 ( 0.7393) sun.7b24 > svr4.nfs: 116 read 1024 bytes @ 73728

142 51.090854 (19.2594) sun.7b23 > svr4.nfs: 116 read 1024 bytes @ 65536
143 51.830939 ( 0.7401) sun.7b24 > svr4.nfs: 116 read 1024 bytes @ 73728

144 71.090305 (19.2594) sun.7b23 > svr4.nfs: 116 read 1024 bytes @ 65536
145 71.830155 ( 0.7398) sun.7b24 > svr4.nfs: 116 read 1024 bytes @ 73728

повторные передачи

167 291.824285 ( 0.7400) sun.7b24 > svr4.nfs: 116 read 1024 bytes @ 73728
168 311.083676 (19.2594) sun.7b23 > svr4.nfs: 116 read 1024 bytes @ 65536

сервер перезагрузился

169 311.149476 ( 0.0658) arp who-has sun tell svr4
170 311.150004 ( 0.0005) arp reply sun is-at 8:0:20:3:f6:42

171 311.154852 ( 0.0048) svr4.nfs > sun.7b23: reply ok 1124

172 311.156671 ( 0.0018) sun.7b25 > svr4.nfs: 116 read 1024 bytes @ 66560
173 311.168926 ( 0.0123) svr4.nfs > sun.7b25: reply ok 1124
считывание



Чтобы посмотреть, как работает устойчивый



Пример

Чтобы посмотреть, как работает устойчивый таймер, мы запустим принимающий процесс, который ожидает прихода запроса на соединение от клиента, принимает запрос на соединение, а затем на долго засыпает перед тем, как начать чтение из сети.
Программа sock позволяет установить паузу с помощью опции -P, при этом пауза вставляется между моментом, когда сервер принимает запрос на соединение, и моментом, когда будет осуществлено первое чтение. Мы запустим сервер следующим образом:
svr4 % sock -i -s -P100000 5555
После запуска этой команды сервер будет "спать" 100000 секунд (27,8 часов) перед тем, как начать читать из сети. Клиент запущен на хосте bsdi и осуществляет записи по 1024 байта на порт сервера 5555. На рисунке 22.1 показан вывод команды tcpdump. (Мы удалили все имеющее отношение к установлению соединения.)

1 0.0 bsdi.1027 > svr4.5555: P 1:1025(1024) ack 1 win 4096
2 0.191961 ( 0.1920) svr4.5555 > bsdi.1027: . ack 1025 win 4096
3 0.196950 ( 0.0050) bsdi.1027 > svr4.5555: . 1025:2049(1024) ack 1 win 4096
4 0.200340 ( 0.0034) bsdi.1027 > svr4.5555: . 2049:3073(1024) ack 1 win 4096
5 0.207506 ( 0.0072) svr4.5555 > bsdi.1027: . ack 3073 win 4096
6 0.212676 ( 0.0052) bsdi.1027 > svr4.5555: . 3073:4097(1024) ack 1 win 4096
7 0.216113 ( 0.0034) bsdi.1027 > svr4.5555: P 4097:5121(1024) ack 1 win 4096
8 0.219997 ( 0.0039) bsdi.1027 > svr4.5555: P 5121:6145(1024) ack 1 win 4096
9 0.227882 ( 0.0079) svr4.5555 > bsdi.1027: . ack 5121 win 4096
10 0.233012 ( 0.0051) bsdi.1027 > svr4.5555: P 6145:7169(1024) ack 1 win 4096
11 0.237014 ( 0.0040) bsdi.1027 > svr4.5555: P 7169:8193(1024) ack 1 win 4096
12 0.240961 ( 0.0039) bsdi.1027 > svr4.5555: P 8193:9217(1024) ack 1 win 4096
13 0.402143 ( 0.1612) svr4.5555 > bsdi.1027: . ack 9217 win 0

14 5.351561 ( 4.9494) bsdi.1027 > svr4.5555: . 9217:9218(1) ack 1 win 4096
15 5.355571 ( 0.0040) svr4.5555 > bsdi.1027: . ack 9217 win 0

16 10.351714 ( 4.9961) bsdi.1027 > svr4.5555: . 9217:9218(1) ack 1 win 4096
17 10.355670 ( 0.0040) svr4.5555 > bsdi.1027: . ack 9217 win 0

18 16.351881 ( 5.9962) bsdi.1027 > svr4.5555: . 9217:9218(1) ack 1 win 4096
19 16.355849 ( 0.0040) svr4.5555 > bsdi.1027: . ack 9217 win 0

20 28.352213 (11.9964) bsdi.1027 > svr4.5555: . 9217:9218(1) ack 1 win 4096
21 28.356178 ( 0.0040) svr4.5555 > bsdi.1027: . ack 9217 win 0

22 52.352874 (23.9967) bsdi.1027 > svr4.5555: . 9217:9218(1) ack 1 win 4096
23 52.356839 ( 0.0040) svr4.5555 > bsdi.1027: . ack 9217 win 0

24 100.354224 (47.9974) bsdi.1027 > svr4.5555: . 9217:9218(1) ack 1 win 4096
25 100.358207 ( 0.0040) svr4.5555 > bsdi.1027: . ack 9217 win 0

26 160.355914 (59.9977) bsdi.1027 > svr4.5555: . 9217:9218(1) ack 1 win 4096
27 160.359835 ( 0.0039) svr4.5555 > bsdi.1027: . ack 9217 win 0

28 220.357575 (59.9977) bsdi.1027 > svr4.5555: . 9217:9218(1) ack 1 win 4096
29 220.361668 ( 0.0041) svr4.5555 > bsdi.1027: . ack 9217 win 0

30 280.359254 (59.9976) bsdi.1027 > svr4.5555: . 9217:9218(1) ack 1 win 4096
31 280.363315 ( 0.0041) svr4.5555 > bsdi.1027: . ack 9217 win 0



Пример

Сейчас мы подробно рассмотрим, как можно избежать синдрома глупого окна и как работает устойчивый таймер. Мы воспользуемся программой sock с отправляющего хоста, sun, который сделает в сеть шесть записей размером 1024 байта:
sun % sock -i -n6 bsdi 7777
Принимающий процесс на хосте bsdi сделает несколько пауз, а именно, перед осуществлением первого считывания пауза продлиться 4 секунды, а между каждым следующим считыванием пауза составит 2 секунды. Получатель считывает данные по 256 байт:
bsdi % sock -i -s -P4 -p2 -r256 7777
Первая пауза позволяет заполнить буфер приемника, что заставляет его остановить передатчик. Так как получатель затем осуществляет маленькие считывания из сети, мы ожидаем, что получатель применит процедуру предотвращения синдрома глупого окна.
На рисунке 22.2 показана временная диаграмма для передачи 6144 байт данных. (Мы удалили все связанное с установлением соединения.)
Нам необходимо отследить следующее: что происходит с приложением, которое считывает данные в каждый момент времени, количество байт, находящихся в настоящий момент в приемном буфере, и размер свободного пространства в приемном буфере (в байтах). На рисунке 22.3 приведены эти данные.



Пример

Увидеть, как происходит определение транспортного MTU, можно в том случае, когда промежуточный маршрутизатор имеет MTU меньше чем MTU интерфейсов конечных точек. На рисунке 24.1 показана топология для данного примера.



Пример

Если мы инициируем соединение с использованием программы sock с хоста 4.4BSD vangogh.cs.berkeley.edu, то можем увидеть, как TCP рассчитывает коэффициент масштабирования окна. Приведенный ниже интерактивный вывод показывает два последовательных запуска программы, причем в первом случае устанавливается приемный буфер размером 128000 байт, а во втором приемный буфер установлен в 220000 байт:

vangogh % sock -v -R128000 bsdi.tuc.noao.edu echo
SO_RCVBUF = 128000
connected on 128.32.130.2.4107 to 140.252.13.35.7
TCP_MAXSEG = 512
hello, world вводим эту строку
hello, world здесь она отражена эхом
^D вводим символ конца файла, чтобы закрыть соединение

vangogh % sock -v -R220000 bsdi.tuc.noao.edu echo
SO_RCVBUF = 220000
connected on 128.32.130.2.4108 to 140.252.13.35.7
TCP_MAXSEG = 512
bye, bye вводим эту строку
bye, bye здесь она отражена эхом
^D вводим символ конца файла, чтобы закрыть соединение

На рисунке 24.7 показан вывод команды tcpdump для этих двух соединений. (Мы удалили последние 8 строк для второго соединения, потому что в них нет ничего нового.)

1 0.0 vangogh.4107 > bsdi.echo: S 462402561:462402561(0)
win 65535
<mss 512,nop,wscale 1,nop,nop,timestamp 995351 0>
2 0.003078 ( 0.0031) bsdi.echo > vangogh.4107: S 177032705:177032705(0)
ack 462402562 win 4096 <mss 512>
3 0.300255 ( 0.2972) vangogh.4107 > bsdi.echo: . ack 1 win 65535

4 16.920087 (16.6198) vangogh.4107 > bsdi.echo: P 1:14(13) ack 1 win 65535
5 16.923063 ( 0.0030) bsdi.echo > vangogh.4107: P 1:14(13) ack 14 win 4096
6 17.220114 ( 0.2971) vangogh.4107 > bsdi.echo: . ack 14 win 65535

7 26.640335 ( 9.4202) vangogh.4107 > bsdi.echo: F 14:14(0) ack 14 win 65535
8 26.642688 ( 0.0024) bsdi.echo > vangogh.4107: . ack 15 win 4096
9 26.643964 ( 0.0013) bsdi.echo > vangogh.4107: F 14:14(0) ack 15 win 4096
10 26.880274 ( 0.2363) vangogh.4107 > bsdi.echo: . ack 15 win 65535

11 44.400239 (17.5200) vangogh.4108 > bsdi.echo: S 468226561:468226561(0)
win 65535
<mss 512,nop,wscale 2,nop,nop,timestamp 995440 0>
12 44.403358 ( 0.0031) bsdi.echo > vangogh.4108: S 182792705:182792705(0)
ack 468226562 win 4096 <mss 512>
13 44.700027 ( 0.2967) vangogh.4108 > bsdi.echo: . ack 1 win 65535
все остальное для этого соединения удалено

Примеры FTP



Примеры FTP

Сейчас мы рассмотрим некоторые примеры использования FTP: как осуществляется управление соединением данных, как передаются текстовые файлы с использованием NVT ASCII, как в FTP используется сигнал синхронизации Telnet для прекращения процесса передачи. В завершение мы рассмотрим "анонимный FTP" (anonymous FTP).



Примеры идентификации



Примеры идентификации

Каждая переменная в MIB должна быть идентифицирована, когда SNMP обращается к ней, чтобы получить или установить ее значение. Во-первых, обращение осуществляется только к листовым узлам (листовой узел в древовидной структуре - любой самый удаленный элемент от корня). SNMP не работает с целыми рядами или колонками таблицы. Возвращаясь к рисунку 25.7, мы видим, что листовыми узлами дерева, являются те четыре, что мы описали на рисунке 25.8, и два на рисунке 25.9. Узлы mib, udp, udpTable и udpEntry не являются листовыми узлами.



Примеры NFS



Примеры NFS

Давайте воспользуемся tcpdump, чтобы посмотреть, какие NFS процедуры привлекаются клиентом для обычных операций с файлом. Когда tcpdump определяет, что UDP датаграмма содержит RPC вызов (call равен 0 на рисунке 29.1) с портом назначения 2049, он декодирует датаграмму как NFS запрос. Точно так же, если UDP датаграмма содержит RPC отклик (reply равен 1 на рисунке 29.2) с портом источника равным 2049, он декодирует датаграмму как NFS отклик.



Примеры "оставайся в живых"



Примеры "оставайся в живых"

Сейчас мы просмотрим сценарии 2, 3 и 4 из предыдущего раздела, чтобы рассмотреть обмен пакетами при использовании опции "оставайся в живых".



Примеры Rlogin



Примеры Rlogin

Мы рассмотрим два примера: первый показывает протокол клиент-сервер в начале Rlogin сессии, а второй показывает, что произойдет при вводе клавиши прерывания, для того чтобы остановить процесс, работающий на сервере и генерирующий много вывода. На рисунке 19.2 показан обычный поток данных по Rlogin сессии.



Примеры SMTP



Примеры SMTP

В предыдущем разделе показана обычная доставка почты; сейчас рассмотрим, как для доставки почты записи используются MX, а также проиллюстрируем работу команд VRFY и EXPN.



Примеры Telnet



Примеры Telnet

Сейчас мы рассмотрим обсуждение опций Telnet, вместе с тремя различными режимами функционирования: символ за один раз, реальный линейный режим и режим передачи строки за один раз. Также мы увидим, что происходит, когда пользователь прекращает работу процесса на сервере с использованием символа прерывания.



Принцип доставки почты SMTP



Рисунок 28.2 Принцип доставки почты SMTP.


MTA добавляет первые три строки, а также Received: и Message-Id:, а следующие девять строк генерируются пользовательским агентом.