В процессе повторной передачи пакета могут возникнуть проблемы. Скажем, пакет передан, тайм-аут отработан, RTO экспотенциально увеличен, как показано в разделе "Простой пример использования тайм-аутов и повторных передач" этой главы, пакет передан повторно с большим RTO и получено подтверждение. Соответствует ли это подтверждение первой передаче или второй? Это называется проблемой двусмысленности повторной передачи (retransmission ambiguity problem) .
[Karn and Partridge 1987] указывает, что когда применяется тайм-аут и повторная передача, мы не можем обновить оценочные функции RTT, когда, в конце концов, прибывает подтверждение на повторно переданные данные. Это потому, что мы не знаем, которой передаче соответствует подтверждение (ACK). (Возможно, первая передача была задержана, но не была отброшена, или был задержан ACK на первую передачу.)
Так как данные были повторно переданы и к RTO было применено экспотенциальное наращивание, мы повторно используем экспотенциально увеличенный RTO для следующей передачи. Новый RTO не рассчитывается до тех пор, пока не будет получено подтверждение на сегмент, который не отправлялся повторно.
Медленный старт, который мы описали в разделе "Медленный старт" главы 20, это способ первоначально установить поток данных по соединению. Однако, в это же самое время мы достигнем предела у промежуточного маршрутизатора, при котором пакеты будут отбрасываться. Предотвращение переполнения это способ, позволяющий предотвратить потерю пакетов. Подробности можно найти в [Jacobson 1988].
Предположение, на котором строится этот алгоритм, заключается в том, что из-за различных повреждений теряется очень малое число пакетов (значительно меньше чем 1%), поэтому потеря пакетов сигнализирует о том, что в каком-либо месте сети между источником и назначением появилось переполнение. Существуют два признака, по которым можно определить, что пакеты теряются: появление тайм-аутов и получение дублированных ACK. (Мы видели последнее в разделе "Пример переполнения" этой главы. Если же использовать тайм-аут как показатель возникновения переполнения, то нам потребуется хороший алгоритм расчета RTT, примерно такой, как описан в разделе "Определение времени возврата".)
Предотвращение переполнения и медленный старт это независимые друг от друга алгоритмы, более того, работающие с различными объектами. Однако, когда возникает переполнение, мы хотим замедлить скорость передачи пакетов по сети, а затем использовать медленный старт, чтобы начать все с начала. На практике эти алгоритмы используются вместе.
Предотвращение переполнения и медленный старт требуют, чтобы для каждого соединения были определены две переменные: окно переполнения, cwnd, и размер порога медленного старта, ssthresh. Вместе алгоритмы работают следующим образом:
Инициализация заданного соединения устанавливает cwnd в один сегмент, а ssthresh в 65535 байт. Подпрограмма вывода TCP определит, какое из значений меньше: cwnd или окно, объявленное получателем и никогда не пошлет больше минимального значения. Предотвращение переполнения это способ контролировать поток данных, со стороны отправителя, тогда как объявление окна это способ контролировать поток данных, со стороны получателя. Первый основан на оценке отправителем того, насколько переполнена сеть, тогда как последний связан с величиной доступного буферного пространства у получателя для данного соединения. Когда возникает переполнение (на что указывает тайм-аут или получение дублированных ACK), одна половина текущего размера окна (меньшее значение из величин cwnd и размера окна, объявленного получателем, но по меньшей мере два сегмента) сохраняется в ssthresh. Более того, если мы узнали о переполнении с помощью тайм-аута, cwnd устанавливается в один сегмент (то есть осуществляется медленный старт). Когда новые данные подтверждены удаленным концом, cwnd увеличивается, однако способ этого увеличения зависит от того, работает ли алгоритм медленного старта или предотвращения переполнения. Если cwnd меньше или равно ssthresh, используется медленный старт; иначе используется предотвращение переполнения. Медленный старт продолжается до тех пор, пока мы не достигнем половины пути до того момента где были, когда возникло переполнение (то есть, до того момента пока мы не запишем половину размера окна, которое доставило нам проблемы в шаге 2), после чего используется алгоритм предотвращения переполнения. Медленный старт требует, чтобы cwnd начиналась с одного сегмента и увеличивалась на один сегмент каждый раз при приеме ACK. Как указано в разделе "Медленный старт" главы 20, это открывает окно экспотенциально: посылается один сегмент, затем два, затем четыре и так далее. Предотвращение переполнения требует, чтобы cwnd увеличивалась на 1/cwnd плюс меньшая дробная часть размера сегмента (размер сегмента, поделенный на 8) каждый раз, когда прибывает ACK. (Это ошибка реализации, которая присутствовала во всех релизах 4.3BSD и даже в 4.4BSD. Но этой ошибки нет в будущих реализациях [Floyd 1994]. Обратите внимание на то, что в примерах ниже в главе используется этот термин, потому что примеры исполнялись на реализации с ошибкой [см. рисунок 21.9 и рисунок 21.11]). Это увеличение посредством сложения, по сравнению с экспотенциальным увеличением при медленном старте. Мы хотим увеличивать cwnd по крайней мере на один сегмент за каждый промежуток времени равный времени возврата (вне зависимости от того, сколько ACK было принято за этот RTT), тогда как медленный старт увеличивает cwnd на количество ACK принятых за время возврата. Прибавление меньшей дробной части размера сегмента позволяет быстрее открывать большие окна.
Релиз 4.3BSD Tahoe, описанный в [Leffler et al. 1989], осуществляет медленный старт, только если удаленный конец находится в другой сети. Это было изменено в релизе 4.3BSD Reno таким образом, что медленный старт осуществляется всегда.
На рисунке 21.8 приведено описание медленного старта и предотвращения переполнения. Мы показали размер cwnd и ssthresh в блоках сегментов, тогда как в действительности их размер измеряется в байтах.
Существует невероятно популярная форма использования FTP. Она называется анонимный FTP (anonymous FTP). Если эта форма поддерживается сервером, она позволяет любому получить доступ к серверу и использовать FTP для передачи файлов. С помощью анонимного FTP можно получить доступ к огромному объему свободно распространяемой информации.
Тут возникает еще одна проблема, которая заключается в том, что очень сложно найти то, что нужно в этом море информации. Кратко это описано в разделе "Archie, WAIS, Gopher, Veronica и WWW" главы 30.
Воспользуемся анонимным FTP, чтобы получить файл опечаток для этой книги с хоста ftp.uu.. Чтобы использовать анонимный FTP, мы входим в систему с именем пользователя "anonymous" (чтобы выучить, как пишется это слово, попробуйте повторить его несколько раз). Когда появляется приглашение ввести пароль, мы вводим наш адрес электронной почты.
sun % ftp ftp.uu.net
Connected to ftp.uu.net.
220 ftp.UU.NET FTP server (Version 2.OWU(13) Fri Apr 9 20:44:32 EDT 1993) ready.
Name (ftp.uu.net:rstevens): anonymous
331 Guest login ok, send your complete e-mail address as password.
Password: мы вводим rstevens@noao.edu; это не отображается эхом
230-
230- Welcome to the UUNET archive.
230- A service of UUNET Technologies Inc, Falls Church, Virginia
230- For information about UUNET, call +1 703 204 8000, or see the files
230- in /uunet-info
здесь еще несколько приветственных строк
230 Guest login ok, access restrictions apply.
ftp> cd published/books переходим в нужную директорию
250 CWD command successful.
ftp> binary будем использовать двоичный формат файла
200 Type set to I.
ftp> get stevens.tcpipiv1.errata.Z получаем файл
200 PORT command successful.
150 Opening BINARY mode data connection for stevens.tcpipiv1.errata.Z (105 bytes).
226 Transfer complete. (у вас может быть другой размер файла)
local: stevens.tcpipiv1.errata.Z remote: stevens.tcpipiv1.errata.Z
105 bytes received in 4.1 seconds (0.83 Kbytes/s)
ftp> quit
221 Goodbye.
sun % uncompress stevens.tcpipiv1.errata.Z
sun % more stevens.tcpipiv1.errata
Программа uncompress используется потому, что большинство файлов, доступных через анонимный FTP, сжаты с использованием Unix программы compress(1), такие файлы имеют расширение .Z. Эти файлы должны быть переданы в виде двоичных файлов, а не ASCII файлов.
Мы можем объединить вместе некоторые характеристики маршрутизации и системы имен (Domain Name System) с использованием анонимного FTP. В разделе "Запросы указателя" главы 14 мы говорили о запросах указателя в DNS - которые воспринимают IP адреса и возвращают имя хоста. К сожалению, не все администраторы систем корректно конфигурируют свои DNS серверы таким образом, чтобы они отвечали на запросы указателей. Они часто добавляют новые хосты к файлам, необходимым для установления соответствия имя-адрес, однако забывают добавить их в файлы, устанавливающие соответствие адрес-имя. С этим можно столкнуться, работая с программой traceroute, когда она выдает IP адреса вместо имен хостов.
Некоторые анонимные FTP серверы требуют, чтобы клиент имел корректное имя домена. Это позволяет серверу зарегистрировать имя домена и хоста, с который осуществлен заход. Единственная информация, которую может узнать сервер о клиенте из IP датаграммы - это IP адрес клиента. Сервер осуществляет запрос указателя, чтобы узнать доменное имя клиента. Если DNS сервер, отвечающий за хост клиента, не сконфигурирован корректно, запрос указателя не сработает.
Давайте смоделируем подобную ошибку. Изменим IP адрес хоста slip (см. рисунок на внутренней стороне обложки) на 140.252.13.67. Это нормальный IP адрес для нашей подсети, однако его нет на DNS сервере домена noao.edu. Изменим IP адрес назначения SLIP канала на bsdi на 140.252.13.67. Добавим пункт в таблицу маршрутизации на sun, который будет направлять датаграммы для 140.252.13.67 на маршрутизатор bsdi. (Обратитесь к описанию этой таблицы маршрутизации, которое приведено в разделе "Принципы маршрутизации" главы 9.)
Хост slip доступен по Internet, потому что, как мы видели в разделе "RIP: протокол обмена информацией о маршрутизации" главы 10, маршрутизаторы gateway и netb все еще посылают датаграммы, которые предназначены в подсеть 140.252.13, на маршрутизатор sun. Наш маршрутизатор sun знает, что делать с этими датаграммами, в соответствии с пунктом маршрутизации, который мы сделали в шаге номер 3. Таким образом, мы создали хост, который полностью подключен к Internet, однако не имеющий корректного имени домена. Таким образом, запрос указателя для IP адреса 140.252.13.67 не будет работать. А сейчас воспользуемся анонимным FTP на сервер, который, как мы знаем, требует корректного имени домена.
slip % ftp ftp.uu.net
Connected to ftp.uu.net.
220 ftp.UU.NET FTP server (Version 2.OWU(13) Fri Apr 9 20:44:32 EDT 1993) ready.
Name (ftp.uu.net:rstevens): anonymous
530- Sorry, we're unable to map your IP address 140.252.13.67 to a hostname
530- in the DNS. This is probably because your nameserver does not have a
530- PTR record for your address in its tables, or because your reverse
530- nameservers are not registered. We refuse service to hosts whose
530- names we cannot resolve. If this is simply because your nameserver is
530- hard to reach or slow to respond then try again in a minute or so, and
530- perhaps our nameserver will have your hostname in its cache by then.
530- If not, try reaching us from a host that is in the DNS or have your
530- system administrator fix your servers.
530 User anonymous access denied..
Login failed.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> quit
221 Goodbye.
(К сожалению, мы не можем найти имя хоста, соответствующее вашему IP адресу. Возможно, это потому, что у вашего сервера имен нет в таблице PTR записи, соответствующей вашему адресу, или ваш сервер не зарегистрирован. Мы не работаем с хостами, для которых мы не можем определить имя домена. Если проблема в том, что ваш DNS сервер медленно отвечает или до него сложно достучаться, попробуйте еще раз через минуту. Может быть, в этот раз DNS сервер уже будет иметь ваше имя в своем кэше. Если дело не в этом, попробуйте зайти к нам с хоста, который корректно зарегистрирован в DNS, или попросите администратора починить ваш сервер.) Сообщение об ошибке говорит само за себя.
Многое из того, что показано этой книге, было получено с использованием анонимного FTP. Проблема заключается в том, чтобы найти FTP узел, на котором находится необходимая программа. Иногда мы даже не знаем точное имя файла, однако знаем какое-либо ключевое слово, которое может появиться в имени файла.
Archie предоставляет информацию о тысячах FTP серверов на бескрайних просторах Internet. Мы можем получить доступ к этой информации, зайдя на сервер Archie и осуществив поиск файла, имя которого содержит указанное регулярное выражение. В ответ появится список серверов, для которых было найдено совпадение с именами файлов. Затем мы используем анонимный FTP, чтобы получить файл.
Существует много Archie серверов по всему миру. Стартовая точка - Telnet заход на ds.internic.net, под именем archie и исполнение команды servers. При этом будет возвращен список всех Archie серверов и их положений.
Средства, которые мы описали в двух предыдущих разделах, - Finger, Whois и сервис белых страниц предоставляют информацию о местонахождении персон. Существуют другие средства, которые позволяют находить файлы и документы. В следующем разделе дается краткое описание этих средств. Мы приводим только краткое описание, потому что рассмотрение в деталях каждого из них может занять целую книгу. Новые программы разрабатываются постоянно. [Obraczka, Danzig, and Li 1993] описывает сервисы поиска ресурсов в Internet.
Формальная спецификация SNMP использует абстрактную форму записи (ASN.1 - Abstract Syntax Notation 1), и кодирование бит в SNMP сообщениях (рисунок 25.2) на основе основных правил кодирования (BER - Basic Encoding Rules). В отличие от большинства публикаций, описывающих SNMP, мы специально оставили обсуждение ASN.1 и BER на самый конец. Если рассказать о них в самом начале, читатель может неправильно понять реальное назначение SNMP - управление сетью. В этом разделе мы дадим только краткий обзор этих двух тем. Глава 8 [Rose 1990] описывает ASN.1 и BER более подробно.
ASN.1 это формальный язык, который описывает данные и характеристики данных. Он не определяет то, как эти данные хранятся или кодируются. Все поля в MIB и SNMP сообщениях описываются с использованием ASN.1. Например, ASN.1 определение типа данных IpAddress из SMI выглядит следующим образом:
IpAddress ::=
[APPLICATION 0] -- in network-byte order
IMPLICIT OCTET STRING (SIZE(4))
Точно так же, в MIB мы находим следующее определение простых переменных:
udpNoPorts OBJECT-TYPE
SYNTAX Counter
ACCESS read-only
STATUS mandatory
DESCRIPTION
"The total number of received UDP datagrams for which there
was no application at the destination port."
::= { udp 2 }
Определение таблиц, использующих SEQUENCE и SEQUENCE OF, более сложное.
С использованием подобных ASN.1 определений существует множество способов закодировать данные в поток битов при передаче. SNMP использует BER. Для представления маленьких целых чисел, таких как 64, с использованием BER требуется 3 байта. Один байт содержит значение целого, следующий байт говорит, сколько байтов используется, чтобы хранить целое (1), и последний байт содержит двоичное значение.
К счастью, подробности ASN.1 и BER важны только для разработчиков SNMP. Они не обязательны для понимания того, как осуществляется управление сетью.
С использованием команды VRFY в SMTP, вместе с протоколом Finger и протоколом Whois можно определить положение пользователей в Internet. Это напоминает использование белых страниц в телефонной книге, когда необходимо найти чей-нибудь телефонный номер. В настоящее время существуют широко доступные средства, однако проводятся исследования, призванные улучшить этот тип сервиса.
[Schwartz and Tsirigotis 1991] приводит дополнительную информацию о различных сервисах белых страниц, которые появляются в Internet. Один из них Netfind; к нему можно получить доступ по Telnet на хосте bruno.cs.colorado.edu или ds.internic.net (имя пользователя netfind).
RFC 1309 [Weider, Reynolds, and Heker 1992] предоставляет краткое описание службы директорий OSI, которая называется X.500, где приводится сравнение отличие с текущими технологиями Internet (Finger и Whois).
Одна из характеристик NFS (критики NFS называют это бородавкой, а не характеристикой) заключается в том, что NFS сервер безразличен. Сервер не заботится о том, какие клиенты получают доступ и к каким файлам. Заметьте, что в списке NFS процедур, показанных ранее, нет процедуры открытия или закрытия. Процедура LOOKUP напоминает открытие, однако сервер никогда не знает, осуществил ли клиент обращение к файлу, после того как был сделан LOOKUP.
Причина такого "безразличного поведения" заключается в том, чтобы упростить восстановление после выхода из строя сервера, после того как он сломался и перезагрузился.
Народная мудрость гласит, что лучше использовать большие пакеты [Mogul 1993, Sec.15.2.8], потому что отправка меньшего количества больших пакетов "дешевле", чем отправка большего количества маленьких пакетов. (Подразумевается, что пакеты не настолько велики, чтобы вызвать фрагментацию.) Не все согласны с этим положением [Bellovin 1993].
Представьте себе следующий пример. Мы посылаем 8192 байта через четыре маршрутизатора, каждый из которых подключен к телефонной линии T1 (1544000 бит/сек). Во-первых, мы используем два пакета размером 4096 байт, как показано на рисунке 24.3.
В настоящее время почта Internet заметно меняется. Вспомните, что почта Internet состоит из трех частей: конверт, заголовки и тело сообщения. Появляются новые SMTP команды, которые изменяют конверт, в заголовках могут быть использованы не-ASCII символы, а к телу добавляются структуры (MIME). В этом разделе мы по порядку рассмотрим расширение каждой из трех частей.
В тексте не приводится достаточно жесткого разграничения между алгоритмом быстрой повторной передачи и быстрого восстановления. Это два абсолютно независимых алгоритма. Алгоритм быстрой повторной передачи вступает в действие, когда TCP определяет потерю сегмента и номер потерянного сегмента по наличию небольшого количества последователььных дублированных подтверждений (ACK). Потерянный сегмент передается повторно. Алгоритм быстрого востановления говорит, что после быстрой повторной передачи необходимо осуществить предотвращение переполнения, а не медленный старт. Алгоритм быстрой повторной передачи впервые появился в 4.3BSD Tahoe, однако за ним неправильно следовал медленный старт. Алгоритм быстрого восстановления впервые был применен в 4.3BSD Reno.
В 1990 году [Jacobson 1990b] алгоритм предотвращения переполнения был модифицирован. Мы уже видели эти модификации в действии в примере переполнения (раздел "Пример переполнения" этой главы).
Перед тем как познакомиться с этими изменениями представьте, что TCP требует сгенерировать немедленное подтверждение (дублированный ACK), когда принят поврежденный сегмент. Этот дублированный ACK не должен быть задержан. Цель дублированного ACK заключается в том, чтобы сообщить удаленному концу о том, что сегмент был получен поврежденным, и сообщить, какой ожидается номер последовательности.
Так как мы не знаем, было ли дублирование ACK вызвано потерей сегмента или просто тем, что изменился порядок следования сегментов, мы ожидаем прихода небольшого количества дублированных ACK. Это означает, что если сегменты просто пришли в другом порядке, будет получено только один или два дублированных ACK перед тем, как перемешанные сегменты будут обработаны, после чего будет сгенерирован новый ACK. Если же последовательно пришло три или более дублированных ACK, это уже является признаком того, что сегмент был потерян (раздел "Пример переполнения"). Мы осуществляем повторную передачу отсутствующего сегмента, не ожидая истечения таймера повторной передачи. Также мы осуществляем предотвращение переполнения, но не медленный старт.
На рисунке 21.7 мы видели, что медленный старт не осуществлялся после того, как было принято три дублированных ACK. Вместо этого отправитель осуществил повторную передачу, за которой следует три сегмента новых данных (сегменты 67, 69 и 71), перед тем как были получены подтверждения на повторную передачу (сегмент 72).
Причина того, что в этом случае не был применен медленный старт, заключается в том, что получение дублированных ACK сообщило нечто большее, нежели просто о потере одного пакета. Так как получатель может только генерировать дублированные ACK, когда прибывает еще один сегмент, можно сказать, что этот сегмент вышел из сети и находится в буфере получателя. Таким образом, данные все еще двигаются между двумя концами, и мы не хотим внезапно уменьшить поток, воспользовавшись медленным cтартом.
Алгоритм функционирует следующим образом.
Когда принят третий дублированный ACK, ssthresh устанавливается равным половине текущего окна переполнения, cwnd.
Передается отсутствующий сегмент.
Значение cwnd устанавливается в значение ssthresh плюс утроенное значение размера сегмента.
Каждый раз когда прибывает дублированный ACK, cwnd увеличивается на размер сегмента, и передается пакет (если это разрешено новым значением cwnd). Когда прибывает следующий ACK, который подтверждает новые данные, устанавливается cwnd равное ssthresh (значение, установленное в шаге 1). Это должно быть ACK на повторную передачу из шага 1, пришедшее через одно время возврата после повторной передачи. Этот ACK должен также подтверждать все промежуточные сегменты, отправленные между потерянным пакетом и получением первого дублированного ACK. Этот шаг осуществляется при предотвращении переполнения, так как мы наполовину замедлили скорость, с которой производилась передача в тот момент, когда пакет был потерян.Мы увидим, что произойдет с переменными cwnd и ssthresh, в следующем разделе.
Эта диаграмма показывает, что количество UDP датаграмм, доставленных приложению (udpInDatagrams), можно получить как количество UDP датаграмм, доставленных от IP к UDP, минус udpInErrors, минус udpNoPorts. Количество UDP датаграмм, доставленных в IP (udpOutDatagrams), это количество, переданное в UDP от приложения. Можно сделать вывод, что udpInDatagrams не включает в себя udpInErrors или udpNoPorts.
Эти диаграммы были использованы в процессе разработки MIB, для проверки того, что все пути данных для пакета были учтены. [Rose 1994] показывает диаграммы зависимостей для всех групп в MIB.
Здесь приводится взаимосвязь между первыми тремя счетчиками, описанными на рисунке 25.8. Диаграммы зависимостей [Case and Partridge 1989] иллюстрируют взаимосвязь между различными MIB переменными в заданной группе. На рисунке 25.10 показана диаграмма зависимостей для UDP группы.
Сейчас мы вернемся к некоторым проблемам, которые были рассмотрены раньше в этой книге, и попробуем использовать SNMP, для того чтобы понять, что все-таки произошло.
При общении между двумя MTA используется NVT ASCII. Команды посылаются клиентом серверу, а сервер отвечает с помощью цифровых кодов и опциональных текстовых строк (для чтения человеком). Это несколько напоминает сценарий, который мы видели для FTP в предыдущей главе.
Клиент может послать серверу небольшое количество команд: меньше дюжины. (Для сравнения, FTP имеет более сорока команд.) Вместо того чтобы описывать команды одну за другой, мы начнем с простого примера, для того чтобы показать что происходит, когда отправляется почта.
Мы можем убедиться в том, что таблица имеет организацию колонка-строка, воспользовавшись программой, которая отправляет запросы, для того чтобы пройти через таблицу слушающего процесса UDP. Мы начнем с того, что спросим следующую переменную после udpTable. Так как это не листовой объект, мы не можем указать объект, однако оператор get-next все равно возвращает следующий объект в таблице. Затем мы продолжим движение по таблице, так как агент возвращает следующую переменную, в соответствии с порядком столбец-строка:
sun % snmpi -a gateway -c secret
snmpi> next udpTable
udpLocalAddress.0.0.0.0.67=0.0.0.0
snmpi> next udpLocalAddress.0.0.0.0.67
udpLocalAddress.0.0.0.0.161=0.0.0.0
snmpi> next udpLocalAddress.0.0.0.0.161
udpLocalAddress.0.0.0.0.520=0.0.0.0
snmpi> next udpLocalAddress.0.0.0.0.520
udpLocalPort.0.0.0.0.67=67
snmpi> next udpLocalPort.0.0.0.0.67
udpLocalPort.0.0.0.0.161=161
snmpi> next udpLocalPort.0.0.0.0.161
udpLocalPort.0.0.0.0.520=520
snmpi> next udpLocalPort.0.0.0.0.520
snmpInPkts.0=59 здесь мы закончили просмотр таблицы слушающего процесса UDP
Мы видим, что порядок, возвращенный в данном примере, соответствует порядку, приведенному на рисунке 25.14.
Как менеджер может определить, что он достиг конца таблицы? Так как ответ на оператор get-next содержит имя следующего пункта в MIB после таблицы, менеджер может сказать, когда имя изменилось. В нашем примере последний пункт в таблице слушающего процесса UDP следует за переменной snmpInPkts.
Как мы говорили ранее, группа UDP содержит четыре переменные, и одну таблицу из двух переменных. На рисунке 25.8 приведены четыре переменные.
Имя | Тип данных | R/W | Описание |
udpInDatagrams | Counter | Количество UDP датаграмм, доставленных пользовательским процессам. | |
udpNoPorts | Counter | Количество доставленных UDP датаграмм, для которых не оказалось пользовательского процесса на порте назначения. | |
udpInErrors | Counter | Количество недоставленных UDP датаграмм не по причине того, что на порте назначения не оказалось приложения (например, ошибка контрольной суммы UDP). | |
udpOutDatagrams | Counter | Количество отправленных UDP датаграмм. |
Мы показали емкость канала в байтах, потому что именно так эта величина обычно рассчитывается на каждом конце соединения для определения размеров буферов и размеров окон.
Сети с большой емкостью канала называются сетями с повышенной пропускной способностью (LFN - long fat networks, произносится как "elephant(s)", elephant (англ.) - слон), а TCP соединения, работающие на LFN, называются каналами с повышенной пропускной способностью (long fat pipe). Возвращаясь назад к рисункам 20.11 и 20.12, можно сказать, что эти каналы могут быть расширены в горизонтальном направлении (большие RTT) или в вертикальном направлении (большая ширина полосы передачи) или в обоих направлениях. Однако, с подобными каналами с повышенной пропускной способностью возникают некоторые проблемы. Размер окна TCP находится в 16-битном поле TCP заголовка, ограничивая размер окна величиной равной 65535 байт. Как видно из последней колонки на рисунке 24.5, существующие сети уже требуют большего окна, чем 65535, для достижения максимальной пропускной способности. Опция масштабирования окна, описанная в разделе "Опция масштабирования окна" этой главы, решает эту проблему. Пакеты, теряемые в LFN, могут значительно уменьшить пропускную способность. Если потерян только один сегмент, алгоритм быстрой передачи и быстрого восстановления, который мы описали в разделе "Быстрая повторная передача и алгоритм быстрого восстановления" главы 21, сделает так, что канал не сузится. Однако, даже при использовании этого алгоритма, потеря больше чем одного пакета внутри окна обычно приводит к тому, что канал сужается. (Если канал сузился, снова используется медленный старт, что в несколько раз увеличивает время возврата, прежде чем канал будет снова заполнен.) Чтобы обработать потерю нескольких пакетов внутри окна, в RFC 1072 [Jacobson and Braden 1988] было предложено использовать cелективные подтверждения (SACK). Однако, начиная с RFC 1323, от использования этой характеристики отказались, потому что авторы обнаружили несколько технических проблем, которые необходимо решить перед включением этой опции в TCP. В разделе "Пример RTT" главы 21 мы видели, что большинство TCP реализаций измеряют только одно время задержки на окно. Они не измеряют RTT для каждого сегмента. Однако для функционирования в LFN требуется лучшее измерение RTT. Опция временной марки, которая описана в разделе "Опция временной марки" этой главы, позволяет оценить время передачи нескольких сегментов, включая повторно переданные. TCP идентифицирует каждый байт данных уникальным 32-битным номером последовательности. Что произойдет, если сегмент, задержанный в сети, появится после того как соединение, которому он принадлежал, уже закрыто, и когда установлено новое соединение между теми же двумя хостами и теми же номерами портов? Во-первых, вспомним, что поле TTL в IP заголовке содержит максимальное время жизни любой IP датаграммы - 255 пересылок или 255 секунд (что кончится первым). В разделе "Диаграмма состояний передачи TCP" главы 18 мы определили, что максимальное время жизни сегмента (MSL) это параметр, зависящий от реализации и используемый для того, чтобы не возникла подобная ситуация. Рекомендуемое значение для MSL - 2 минуты (при этом 2MSL будет равно 240 секундам), однако мы видели в разделе "Диаграмма состояний передачи TCP" главы 18, что многие реализации устанавливают MSL в 30 секунд. Еще одна проблема с номерами последовательности TCP возникает при использовании LFN. Так как величина номера последовательности ограничена, тот же самый номер последовательности будет использован повторно после того, как будет передано 4.294.967.296 байт. Что произойдет, если сегмент, содержащий байт с номером последовательности N, будет задержан в сети и появится позже, когда соединение все еще открыто? Эта проблема появится только в том случае, если тот же самый номер последовательности N повторно используется в течение периода MSL, то есть в том случае, если сеть настолько быстрая, что номер последовательности успевает повториться за время меньшее чем MSL. Для Ethernet необходимо почти 60 минут, чтобы послать такое количество данных, поэтому подобная ситуация не возможна, однако время, необходимое на то, чтобы появился номер последовательности, который уже существует в сети, уменьшается с ростом ширины пропускания сети: для телефонных линий T3 (45 Мбит/сек) требуются 12 минут, для FDDI (100 Мбит/сек) - 5 минут, а для гигабитных сетей (1000 Мбит/сек) - 34 секунды. В данном случае проблема не связана с емкостью канала, а связана с шириной полосы. В разделе "PAWS: защита от перехода номеров последовательности через ноль" этой главы мы описываем способ, с помощью которого можно решить эту проблему: алгоритм PAWS (защита от перехода номеров последовательности через ноль), который использует опцию временной марки TCP.
4.4BSD содержит все опции и алгоритмы, которые мы описываем в следующих разделах: опцию масштабирования окна, опцию временной марки и защиту от перехода номеров последовательности через ноль. Некоторые производители также начинают поддерживать эти опции.
На этом рисунке мы указали в байтах только размер IP и UDP заголовков. Это объясняется тем, что для SNMP сообщений используется кодирование - называемое ASN.1 и BER, которые мы опишем позже в этой главе - в зависимости от типа переменных и их значений.
Значение поля version равно 0. Это значение в действительности равно номеру версии минус единица. (Версия SNMP, которую мы описываем, называется SNMPv1.)
На рисунке 25.3 показано значение для типа блока данных протокола (PDU type). (PDU - это блок данных протокола - Protocol Data Unit, обычно называемый "пакет".)
PDU type | Имя |
0 | get-request |
1 | get-next-request |
2 | set-request |
3 | get-response |
4 | trap |
XID вызова просто копируется в XID отклика. В поле reply находится 1, по этому полю проводится различие между вызовом и откликом. Поле статуса (status) содержит нулевое значение, если сообщение вызова было принято. (Сообщение может быть отброшено, если номер версии RPC не равен 2 или если сервер не может аутентифицировать клиента.) Поле проверки (verifier) используется в случае защищенного RPC, чтобы указать сервер.
В поле статуса приема (accept status) находится нулевое значение, если все нормально. Ненулевое значение может указывать, например, на неверный номер версии или неверный номер процедуры. Если вместо UDP используется TCP, то, как и в случае сообщения вызова RPC, между TCP заголовком и XID посылается 4-байтовое поле длины.
Отклики состоят из 3-циферных значений в формате ASCII, и необязательных сообщений, которые следуют за числами. Подобное представление откликов объясняется тем, что программному обеспечению необходимо посмотреть только цифровые значения, чтобы понять, что ответил процесс, а дополнительную строку может прочитать человек. Поэтому пользователю достаточно просто прочитать сообщение (причем нет необходимости запоминать все цифровые коды откликов).
Каждая из трех цифр в коде отклика имеет собственный смысл. (В главе 28 мы увидим, что протокол передачи почтовых сообщений - SMTP, использует те же соглашения для своих команд и откликов.) На рисунке 27.3 показаны значения первых и вторых цифр в коде отклика.
Отклик | Описание |
1yz | Положительный предварительный отклик. Действие началось, однако необходимо дождаться еще одного отклика перед отправкой следующей команды. |
2yz | Положительный отклик о завершении. Может быть отправлена новая команда. |
3yz | Положительный промежуточный отклик. Команда принята, однако необходимо отправить еще одну команду. |
4yz | Временный отрицательный отклик о завершении. Требуемое действие не произошло, однако ошибка временная, поэтому команду необходимо повторить позже. |
5yz | Постоянный отрицательный отклик о завершении. Команда не была воспринята и повторять ее не стоит. |
x0z | Синтаксическая ошибка. |
x1z | Информация. |
x2z | Соединения. Отклики имеют отношение либо к управляющему, либо к соединению данных. |
x3z | Аутентификация и бюджет. Отклик имеет отношение к логированию или командам, связанным с бюджетом. |
x4z | Не определено. |
x5z | Состояние файловой системы. |
Сервер всегда осуществляет активное открытие соединения данных. Обычно сервер также осуществляет активное закрытие соединения данных, за исключением тех случаев, когда клиент отправляет файл на сервер в потоковом режиме, который требует, чтобы клиент закрыл соединение (что делается с помощью уведомления сервера о конце файла).
Если клиент не выдает команду PORT, сервер осуществляет активное открытие на тот же самый номер порта, который использовался клиентом для управляющего соединения (1173 в данном примере). В этом случае все работает корректно, так как номера порта сервера для двух соединений различны: один 20, другой 21. Тем не менее, в следующем разделе мы посмотрим, почему современные реализации не поступают таким образом.
Команда tcpdump декодирует NFS запрос или отклик, также она печатает поле XID для клиента, вместо номера порта. Поле XID в строках 1 и 2 равно 0x7aa6.
Имя файла /nfs/bsdi/usr/rstevens/hello.c обрабатывается функцией открытия в ядре клиента по одному элементу имени за раз. Когда функция открытия достигает /nfs/bsdi/usr, она определяет, что это точка монтирования файловой системы NFS.
В строке 1 клиент вызывает процедуру GETATTR, чтобы получить атрибуты директории сервера, которую смонтировал клиент (/usr). Этот RPC запрос содержит 104 байта данных, помимо IP и UDP заголовков. Отклик в строке 2 возвращает OK и содержит 96 байт данных, помимо IP и UDP заголовков. Мы видим на этом рисунке, что минимальное NFS сообщение содержит примерно 100 байт данных.
В строке 3 клиент вызывает процедуру LOOKUP для файла rstevens и получает отклик OK в строке 4. LOOKUP указывает имя файла rstevens и описатель файла, который был сохранен ядром, когда монтировалась удаленная файловая система. Отклик содержит новый описатель файла, который используется в следующем шаге.
В строке 5 клиент осуществляет LOOKUP файла hello.c с использованием описателя файла из строки 4. Он получает другой описатель файла в строке 6. Этот новый описатель файла как раз то, что клиент использует в строках 7 и 9, чтобы обратиться к файлу /nfs/bsdi/usr/rstevens/hello.c. Мы видим, что клиент осуществляет LOOKUP для каждого компонента имени в пути к открываемому файлу.
В строке 7 клиент еще раз исполняет GETATTR, затем следует READ в строке 9. Клиент запрашивает 1024 байта, начиная со смещения равного 0, однако получает данных меньше чем 1024 байта. (После вычитания размеров RPC полей и других значений, возвращенных процедурой READ, в строке 10 возвращаются 38 байт данных. Это как раз размер файла hello.c.)
В этом примере пользовательский процесс ничего не знает об этих NFS запросах и откликах, которые осуществляются ядром. Приложение всего лишь вызывает функцию открытия ядра, которая вызывает обмен 3 запросами и 3 откликами (строки 1-6), а затем вызывает функцию чтение ядра, которая вызывает 2 запроса и 2 отклика (строки 7-10). Для приложения клиента, файл, находящийся на NFS сервере, прозрачен.
При смене директории клиент вызывает процедуру GETATTR дважды (строки 1-4). Когда мы создаем новую директорию, клиент вызывает процедуру GETATTR (строки 5 и 6), затем LOOKUP (строки 7 и 8, чтобы проверить, что такой директории не существует), затем MKDIR, чтобы создать директорию (строки 9 и 10). Отклик OK в строке 8 не означает, что директория существует. Он просто означает, что процедура вернула какое-то значение. tcpdump не интерпретирует значение, возвращаемое NFS процедурами. Команда просто печатает OK и количество байт данных в отклике.
Для интерактивных пользователей подобная задержка отклика на ввод символа Control-S нежелательна.
Однако, иногда приложения, запущенные на сервере, должны интерпретировать каждый байт ввода, и они не хотят, чтобы клиент использовал символы Control-S и Control-Q каким-то особенным образом. (Редактор emacs является примером приложения, которое использует эти два символа как свои собственные команды.) В подобном случае сервер может сообщить клиенту, поддерживает ли он контроль потока данных или нет.
Положение вещей меняется, когда скорости в сетях достигают гигабитов. [Partridge 1994] описывает гигабитные сети более подробно. Здесь мы рассмотрим различие между задержкой (латенсией) и шириной полосы [Kleinrock 1992].
Представьте себе процесс отправки файла размером 1 миллион байт через Соединенные Штаты, с предполагаемой латенсией равной 30 миллисекундам. На рисунке 24.6 показаны два сценария, верхний соответствует использованию телефонной линии T1 (1544000 бит/сек), а нижний подразумевает использование сети 1 гигабит/сек. Время показано по оси ОХ, (отправитель находится слева, а получатель справа), а емкость показана по оси OY. Закрашенный прямоугольник на обоих рисунках - это 1 миллион байт, который необходимо отправить.
Введение
Так как количество сетей растет, сети разнообразным образом объединяются (маршрутизаторы различных поставщиков, хосты со встроенными функциями маршрутизации, терминальные серверы и так далее), задача управления этими системами становится очень важной. В этой главе рассматриваются стандарты, которые используются внутри семейства протоколов Internet, для управления сетью.
Управление сетью в объединенных сетях TCP/IP строится на взаимодействии между станцией управления сетью (менеджер) и элементами сети. Элементами сети могут быть любые объекты, которые используют семейство протоколов TCP/IP: хосты, маршрутизаторы, X терминалы, терминальные сервера, принтеры и так далее. На элементах сети должно быть запущено программное обеспечение, которое называется агентом. Станции управления это обычно рабочие станции с цветным монитором и графическим дисплеем, которые отображают то, что происходит с элементами (которые из них работают, а которые нет, объем траффика по различным каналам за единицу времени и так далее).
Обмен данными, как правило, двусторонний: менеджер просит агента сообщить ему определенное значение (например, "сколько было сгенерировано ICMP ошибок о недоступности порта?"), или агент сообщает менеджеру о каком-либо важном событии ("подключенный интерфейс не работает"). У менеджера должна быть возможность установить переменные в агенте ("измени значение TTL по умолчанию на 64"), помимо того, что менеджер должен иметь возможность считывать переменные от агента.
Управление сетями TCP/IP состоит из трех частей. Информационная база управления (MIB - Management Information Base), которая указывает, какие переменные в элементах сети необходимо обслуживать (информация, которая может быть запрошена и установлена менеджером). RFC 1213 [McCloghrie and Rose 1991] определяет вторую версию, которая называется MIB-II. Установка общей структуры и схемы идентификации, используемой для обращения к переменным в MIB. Это называется структурой информации управления (SMI - Structure of Management Information) и описывается в RFC 1155 [Rose and McCloghrie 1990]. Например, SMI указывает, что счетчик (Counter) это неотрицательное целое число, которое изменяется от 0 до 4294967295 и затем снова возвращается в 0. Протокол, который функционирует между менеджером и элементом, называется простым протоколом управления сетью (SNMP - Simple Network Management Protocol). RFC 1157 [Case et al. 1990] описывает этот протокол. Там же подробно описан формат пакетов, с помощью которых осуществляется обмен. Несмотря на то, что в качестве транспортных протоколов могут быть использованы разные протоколы, обычно с SNMP используется UDP.
Эти RFC определяют то, что в настоящее время называется SNMPv1, или просто SNMP, что мы и обсудим в этой главе. В течение 1993 года были опубликованы дополнительные RFC, которые описывают SNMP Version 2 (SNMPv2), который мы опишем в разделе "SNMP версии 2" этой главы.
В этой главе мы рассмотрим протокол, который используется для общения между менеджером и клиентом, во-первых, а затем посмотрим какие переменные использует агент. Мы опишем информационную базу данных, поддерживаемую агентом (MIB), рассмотрим группы, которые мы уже описали в тексте: IP, UDP, TCP и так далее. Рассмотрим примеры, соответствующие каждому описанию, а в процессе рассмотрения будем обращаться к концепции протоколов, описанных в предыдущих главах.
Протокол
SNMP определяет всего пять типов сообщений, которыми обмениваются менеджер и клиент.
Получить значение одной или нескольких переменных: оператор get-request. Получить следующую переменную после этой или несколько указанных переменных: оператор get-next-request. (Мы опишем то, что имеем в виду под словом "следующий" позже в этой главе.) Установить значение одной или нескольких переменных: оператор set-request. Выдать значение одной или нескольких переменных: оператор get-response. Это сообщение возвращается агентом менеджеру в ответ на операторы get-request, get-next-request и set-request. Уведомить менеджера, когда что-либо произошло с агентом: оператор trap.
Первые три сообщения отправляются от менеджера к агенту, а последние два от агента к менеджеру. (Мы будем называть первые три оператора как get, get-next и set.) На рисунке 25.1 приведены все пять операторов.
Так как четыре из пяти SNMP сообщений реализуются простой последовательностью запрос-отклик (менеджер отправляет запрос, а агент возвращает отклик), SNMP используют UDP. Это означает, что запрос от менеджера может не прибыть к агенту, а отклик от агента может не прибыть к менеджеру. В этом случае менеджер, возможно, отработает тайм-аут и осуществит повторную передачу.
Введение
Приложения, позволяющие осуществить заход удаленным терминалом, очень популярны в Internet. Отпадает необходимость иметь аппаратный терминал к каждому хосту, можно зайти терминалом на один хост, затем удаленным терминалом по сети на любой другой хост (в том случае, если на этом хосте существует открытый бюджет).
В сетях TCP/IP существуют два приложения, позволяющие осуществить терминальный заход. Telnet - стандартное приложение, которое присутствует практически в каждой реализации TCP/IP. Оно может быть использовано для связи между хостами, работающими пол управлением различных операционных систем. Telnet использует согласование опций клиента и сервера, чтобы определить, какие характеристики присутствуют с той и с другой стороны. Программа Rlogin происходит из Berkeley Unix и была разработана для того, чтобы работать только между Unix системами, однако впоследствии эта программа была перенесена и на другие операционные системы.
В этой главе рассматривается и Telnet, и Rlogin. Мы начнем с Rlogin, потому что это приложение работает проще.
Telnet это одно из старейших приложений Internet. Оно появилось в 1969 году в ARPANET. Имя этого приложения является сокращением от "сетевой коммуникационный протокол" (telecommmunications network protocol).
Приложения удаленного терминала используют стандарт клиент-сервер. На рисунке 26.1 показано типичное общение Telnet клиента и Telnet сервера. (Точно такой же рисунок можно нарисовать для Rlogin клиента и Rlogin сервера.)
Введение
FTP это еще одно широко используемое приложение. Оно является стандартом Internet для передачи файлов. Необходимо различать передачу файлов, именно то, что предоставляет FTP, и доступ к файлам, что предоставляется такими приложениями как NFS (Network File System, глава 29). Передача файлов заключается в копировании целого файла из одной системы в другую. Чтобы использовать FTP, необходимо иметь открытый бюджет на сервере, или можно воспользоваться так называемым анонимным FTP (anonymous FTP).
Как и Telnet, FTP был создан для того, чтобы работать между хостами работающими под управлением различных операционных систем, использующих различные структуры файлов и, возможно, различные наборы символов. Telnet, однако, обеспечивает связь между разнородными системами, заставляя каждого участника соединения работать с одним и тем же стандартом: NVT, использующий 7-битный ASCII. FTP сглаживает различия между системами с использованием другого подхода. FTP поддерживает ограниченное количество типов файлов (ASCII, двоичное и так далее) и структуру файлов (поток байтов или ориентированный на запись).
RFC 959 [Postel and Reynolds 1985] является официальной спецификацией FTP. Этот RFC описывает историю и развитиие передачи файлов в течение времени.
Протокол FTP
FTP отличается от других приложений тем, что он использует два TCP соединения для передачи файла. Управляющее соединение устанавливается как обычное соединение клиент-сервер. Сервер осуществляет пассивное открытие на заранее известный порт FTP (21) и ожидает запроса на соединение от клиента. Клиент осуществляет активное открытие на TCP порт 21, чтобы установить управляющее соединение. Управляющее соединение существует все время, пока клиент общается с сервером. Это соединение используется для передачи команд от клиента к серверу и для передачи откликов от сервера. Тип IP сервиса для управляющего соединения устанавливается для получения "минимальной задержки", так как команды обычно вводятся пользователем (рисунок 3.2). Соединение данных открывается каждый раз, когда осуществляется передача файла между клиентом и сервером. (Оно также открывается и в другие моменты, как мы увидим позже.) Тип сервиса IP для соединения данных должен быть "максимальная пропускная способность", так как это соединение используется для передачи файлов.
На рисунке 27.1 показано общение клиента и сервера по двум соединениям.
Введение
Электронная почта (e-mail), несомненно, одно из самых популярных приложений. [Caceres et al. 1991] показывает, что примерно половина всех TCP соединений занята передачей почтовых сообщений с исполььзованием простого протокола передачи почты (SMTP - Simple Mail Transfer Protocol). (С точки зрения количества переданных байт, по FTP соединениям передается значительно больше данных.) [Paxson 1993] обнаружил, что среднее почтовое сообщение содержит примерно 1500 байт данных, однако некоторые сообщения содержат мегабайты данных, потому что электронная почта иногда используется для посылки файлов.
На рисунке 28.1 показан обмен почтой с использованием TCP/IP.
Введение
В этой главе мы рассмотрим сетевую файловую систему (NFS - Network File System), популярное приложение, которое предоставляет приложениям клиентов прозрачный доступ к файлам. Краеугольным камнем NFS является Sun RPC: вызов удаленной процедуры (Remote Procedure Call), что мы и опишем в первую очередь.
Программе клиента не требуется специальных средств, чтобы воспользоваться NFS. Ядро определяет что файл находится на NFS сервере и автоматически генерирует RPC вызов, для того чтобы получить доступ к файлу.
Мы не будем подробно рассматривать, как реализуется доступ к файлам, а рассмотрим, как при этом используются протоколы Internet, особенно UDP.
Вызов удаленной процедуры компании Sun
В большинстве случаев задачи сетевого программирования решаются путем написания программ приложений, которые вызывают функции, предоставляемые системой, чтобы осуществить конкретные сетевые операции. Например, одна функция осуществляет активное открытие TCP, другая пассивное открытие TCP, третья посылает данные по TCP соединению, четвертая устанавливает конкретные опции протокола (включает TCP таймер "оставайся в живых") и так далее. В разделе "Интерфейсы прикладного программирования" главы 1 мы упоминали, что существует два популярных набора функций для сетевого программирования (прикладной программный интерфейс, API), это сокеты и TLI. Программный интерфейс, используемый клиентом, и программный интерфейс, используемый сервером, могут отличаться, так же как и операционные системы, которые функционируют у клиента и сервера. Именно коммуникационный и прикладной протоколы определяют, сможет ли конкретный клиент общаться с сервером. Unix клиент, написанный на C, использующий сокеты в качестве программного интерфейса, и TCP - в качестве коммуникационного протокола, может общаться с сервером на мейнфрейме, написанным на COBOLе с использованием других API и TCP, если оба хоста подключены к сети и оба имеют реализацию TCP/IP.
Обычно клиент посылает серверу команды, а сервер отправляет клиенту отклики. Все рассмотренные нами приложения, - Ping, Traceroute, демоны маршрутизации, клиенты и сервера DNS, TFTP, BOOTP, SNMP, Telnet, FTP, SMTP - все построены именно таким образом.
RPC, вызов удаленной процедуры, реализует иной подход к сетевому программированию. Программа клиента просто вызывает функции в программе сервера. Так это решено с точки зрения программиста, однако в действительности имеет место следующая последовательность действий. Когда клиент вызывает удаленную процедуру, вызывается функция на локальном хосте, которая сгенерирована пакетом RPC. Эта функция называется client stub. client stub упаковывает аргументы процедуры в сетевое сообщение и отправляет сообщение серверу. server stub на хосте сервера получает сетевое сообщение. Аргументы извлекаются из сетевого сообщения, и осуществляется вызов процедуры сервера, написанной прикладным программистом. Функция сервера возвращает управление server stubу, который, в свою очередь, принимает полученные значения, упаковывает их в сетевое сообщение и отправляет сообщение обратно к client stub. client stub возвращает приложению клиента значения из сетевого сообщения.
Сетевое программирование, использующее stubы и библиотечные RPC подпрограммы использует интерфейсы прикладного программирования API (сокеты или TLI), однако пользовательские приложения (программа клиента и процедуры сервера, вызываемые клиентом) никогда не обращаются к API. Приложению клиента достаточно вызывать процедуру сервера, при этом все детали реализации спрятаны пакетом RPC, client stubом и server stubом.
Пакеты RPC имеют следующие положительные стороны. Программирование становится легче, так как не приходится решать задачи сетевого программирования (а если и приходится, то совсем немного). Прикладные программисты просто пишут программу клиента и процедуры сервера, которые вызывает клиент. Если используется ненадежный протокол, такой как UDP, все детали, а именно тайм-ауты и повторные передачи обрабатываются пакетом RPC. Это, в свою очередь, упрощает пользовательское приложение. Библиотека RPC обрабатывает необходимое преобразование аргументов и возвращаемых значений. Например, если аргументы состоят из целых чисел и чисел с плавающей точкой, пакет RPC обработает все различия между представлением целых чисел и чисел с плавающей точкой на клиенте и сервере. Благодаря этому упрощается реализация клиентов и серверов для функционирования в разнородных средах.
Программирование RPC подробно описано в главе 18 [Stevens 1990]. Два наиболее популярных RPC пакета это Sun RPC и RPC пакет в Open Software Foundation's (OSF) Distributed Computing Environment (DCE). Мы рассмотрим, как осуществляется вызов процедуры, как выглядит возвращаемое сообщение и как это соотносится с пакетом Sun RPC, так как именно этот пакет используется в сетевой файловой системе. Версия 2 Sun RPC описана в RFC 1057 [Sun Microsystems 1988a].
Введение
В этой главе мы опишем приложения TCP/IP, которые присутствуют почти во всех реализациях. Некоторые из них просты и их можно описать целиком (Finger и Whois), тогда как другие достаточно сложны (X Window System). Сложные приложения мы рассмотрим, не вдаваясь в подробности, фокусируя свое внимание на то, как они используют протоколы TCP/IP.
В дополнение, мы приведем обзор некоторых средств Internet, которые позволяют определить ресурсы. Это средства, которые помогают нам ориентироваться в Internet, искать отдельные пункты, точное положение которых и точные имена которых не известны.
Протокол Finger
Протокол Finger возвращает информацию об одном или нескольких пользователях на указанном хосте. Это приложение обычно используется, для того чтобы посмотреть, находится ли конкретный пользователь в настоящее время в системе, или чтобы получить имя какого-либо пользователя, чтобы послать ему почту. RFC 1288 [Zimmerman 1991] описывает этот протокол.
Многие узлы не запускают Finger сервер по двум причинам. Во-первых, ошибки в программировании в ранних версиях сервера были одной из точек входа "червяка" в Internet в 1988 году. (RFC 1135 [Reynolds 1989] и [Curry 1992] описывают этого "червяка" более подробно.) Во-вторых, протокол Finger может предоставить подробную информацию о пользователях (login имя, телефонные номера, время последнего логирования и так далее), а эту информацию большинство администраторов считают частной. Раздел 3 RFC 1288 детально описывает аспекты секретности, соответствующие сервису Finger.
Сервер Finger использует заранее известный порт 79. Клиент осуществляет активное открытие на этот порт и отправляет запрос длиной в 1 строку. Сервер обрабатывает запрос, посылает назад вывод и закрывает соединение. Запрос и отклик в формате NVT ASCII, почти так же как мы видели в случае FTP и SMTP.
Обычно большинство пользователей Unix получают доступ к серверу Finger с использованием клиента finger(1), однако мы воспользуемся Telnet клиентом, подсоединимся непосредственно к серверу и рассмотрим команды, которые выдаются клиентом (команды длиной в 1 строку). Если запрос клиента состоит из пустой строки (которая в NVT ASCII передается как CR, за которой следует LF), это воспринимается как запрос на информацию о всех текущих пользователях.
sun % telnet slip finger первые три строки - вывод Telnet клиента
Trying 140.252.13.65 ...
Connected to slip.
Escape character is '^]'.
здесь вводим RETURN в качестве команды клиента Finger
Login Name Tty Idle Login Time Office Office Phone
rstevens Richard Stevens *c0 45 Jul 31 09:13
rstevens Richard Stevens *c2 45 Aug 5 09:41
Connection closed by foreign host. вывод Telnet клиента
Пустые поля с названием офиса и рабочего телефона взяты из необязательных полей в файле пользовательских паролей (которые в данном случае отсутствуют).
Сервер на своей стороне осуществляет активное закрытие, при этом сервер возвращает переменное количество информации, а получение клиентом метки конца файла оповещает клиента о том, что вывод завершен.
Когда в запросе клиента содержится имя пользователя, сервер выдает информацию только об этом пользователе. Здесь приведен еще один пример, вывод Telnet клиента удален:
sun % telnet vangogh.cs.berkeley.edu finger
rstevens это клиент, о котором мы хотим узнать
Login: rstevens Name: Richard Stevens
Directory: /a/guest/rstevens Shell: /bin/csh
Last login Thu Aug 5 09:55 (PDT) on ttyq2 from sun.tuc.noao.edu
Mail forwarded to: rstevens@noao.edu
No Plan.
Когда Finger сервис отключен, клиент, в ответ на активное открытие, получает от сервера RST, так как никакой из процессов не осуществил пассивное открытие на порт 79:
sun % finger @svr4
[svr4.tuc.noao.edu] connect: Connection refused
Некоторые узлы предоставляют определенный сервис на порт 79, однако они просто сообщают информацию, не обращая внимание на клиентские запросы:
sun % finger @att.com
[att.com] это строка вывода от Finger клиента; все остальное от сервера
------------------------------------------------------------
There are no user accounts on the AT&T Internet gateway.
To send email to an AT&T employee, send email to their name
separated by periods at att.com. If the employee has an email
address registered in the employee database, they will receive
email - otherwise, you'll receive a non-delivery notice.
For example: John.Q.Public@att.com1
sun % finger clinton@whitehouse.gov
[whitehouse.gov]
Finger service for arbitrary addresses on whitehouse.gov is not
supported. If you wish to send electronic mail, valid addresses are
"PRESIDENT@WHITEHOUSE.GOV", and "VICE-PRESIDENT@WHITEHOUSE.GOV"2.
На Internet маршрутизаторе фирмы AT&T нет пользовательских бюджетов. Чтобы послать электронную почту работникам AT&T, отправьте ее на имя работника, отделенного точкой от имени att.com. Если работник имеет адрес электронной почты - он ее получит, иначе Вы получите сообщение о недоставке почты. Например, John.Q.Public@att.com. Сервис Finger не поддерживается для адреса whitehouse.gov. Если Вам необходимо послать электронную почту, самые подходящие адреса это "PRESIDENT@WHITEHOUSE.GOV" и "VICE-PRESIDENT@WHITEHOUSE.GOV".
Существует возможность организовать брандмауэр (firewall gateway). Маршрутизатор между организацией и Internet, который фильтрует конкретные IP датаграммы. ([Cheswick and Bellovin 1994] описывает брандмауэры более подробно.) Брандмауэр может быть сконфигурирован таким образом, чтобы отбрасывать входящие датаграммы, которые содержат TCP сегменты на порт 79. В этом случае Finger клиент прекратит работу по тайм-ауту примерно через 75 секунд.
У Finger сервера и Unix клиента finger существуют набор опций. Обратитесь к RFC 1288 и к страницам помощи по finger(1) за более подробной информацией.
RFC 1288 заявляет, что машины с TCP/IP соединениями, которые предоставляют сервер Finger, должны отвечать на запрос клиента содержащий пустую строку, списком всех пунктов, доступных в настоящий момент. Они должны отвечать на запрос клиента содержащий имя, счетчиком или списком доступных пунктов для этого продукта.
Gopher это меню-ориентированное приложение для работы с разнообразными сервисами Internet, таких как Archie, WAIS и анонимный FTP. Gopher это одно из наиболее легко используемых средств, так как его пользовательский интерфейс не зависит от того, какой сервис используется.
Чтобы воспользоваться Gopher, подсоединитесь Telnetом к is.internic.net с именем пользователя gopher.
Группа трансляции адресов поддерживается во всех системах, однако ее ценность значительно уменьшилась, после того как стала использоваться MIB-II. С использованием MIB-II, каждая группа сетевых протоколов (например, IP) содержит свою собственную таблицу трансляции адресов. Для IP это ipNetToMediaTable.
В группе at определена только одна таблица из трех строк, как показано на рисунке 25.19.
Мы можем использовать новую команду, существующую в программе snmpi, чтобы получить содержимое таблицы в целом. Мы запросим маршрутизатор с именем kinetics (который предоставляет маршруты между TCP/IP сетью и сетью AppleTalk), выдать полный ARP кэш. Этот вывод будет находиться в лексикографическом порядке в виде пунктов, находящихся в таблице:
Таблица трансляции адресов, индекс = <atIfIndex>.1.<atNetAddress> | |||
Имя | Тип данных | R/W | Описание |
atIfIndex | INTEGER | · | Номер интерфейса: ifIndex. |
atPhysAddress | PhysAddress | · | Физический адрес. Установка этого параметра в строку с нулевой длиной приводит к тому, что пункт считается некорректным. |
atNetAddress | NetworkAddress | · | IP адрес |
Группа icmp состоит из четырех общих счетчиков (общее количество входящих и исходящих ICMP сообщений и количество входящих и исходящих ICMP сообщений с ошибками) и 22-х счетчиков для различных типов ICMP сообщений: 11 счетчиков на входящие сообщения и 11 счетчиков на исходящие сообщения. Это показано на рисунке 25.26.
Для ICMP сообщений с дополнительными кодами (обратитесь к рисунку 6.3, на котором приведены 15 различных кодов для сообщения о недостижимости пункта назначения) отдельный счетчик для каждого SNMP кода не поддерживается.
Только одна простая переменная определена для этой группы: количество интерфейсов в системе. Рисунок 25.17.
Имя | Тип данных | R/W | Описание |
ifNumber | INTEGER | Количество сетевых интерфейсов в системе. |
Группа ip определяет большое количество переменных и три таблицы. На рисунке 25.21 приведены простые переменные.
Имя | Тип данных | R/W | Описание |
ipForwarding | [1..2] | · | 1 означает, что система перенаправляет IP датаграммы, а 2 означает, что не перенаправляет. |
ipDefaultTTL | INTEGER | · | Значение TTL по умолчанию, когда его не предоставляет транспортный уровень. |
ipInReceives | Counter | Полное количество IP датаграмм, полученных со всех интерфейсов. | |
ipInHdrErrors | Counter | Количество IP датаграмм, отброшенных из-за ошибок в заголовке (например, ошибка контрольной суммы, несовпадение номера версии, истечение TTL и так далее). | |
ipInAddrErrors | Counter | Количество IP датаграмм, отброшенных из-за неправильного адреса назначения. | |
IpForwDatagrams | Counter | Количество IP датаграмм, для которых была сделана попытка перенаправить. | |
ipInUnknownProtos | Counter | Количество локально адресованных IP датаграмм, у которых было неверное поле протокола. | |
ipInDiscards | Counter | Количество принятых IP датаграмм, отброшенных из-за недостаточного размера буфера. | |
ipInDelivers | Counter | Количество IP датаграмм, доставленных соответствующему модулю протокола. | |
ipOutRequests | Counter | Полное количество IP датаграмм, переданных в IP уровень для передачи. Сюда не включены те, которые были посчитаны в ipForwDatagrams. | |
ipOutDiscards | Counter | Количество исходящих IP датаграмм, которые были отброшены из-за отсутствия места в буфере. | |
ipOutNoRoutes | Counter | Количество IP датаграмм, которые были отброшены из-за того, что не был найден маршрут. | |
ipReasmTimeout | INTEGER | Максимальное количество секунд, в течение которого принятые фрагменты ждали повторной сборки. | |
ipReasmReqds | Counter | Количество принятых IP фрагментов, которые должны быть собраны. | |
ipReasmOKs | Counter | Количество успешно собранных IP датаграмм. | |
ipReasmFails | Counter | Количество сбоев в алгоритме повторной сборки IP. | |
ipFragOKs | Counter | Количество успешно фрагментированных IP датаграмм. | |
ipFragFails | Counter | Количество IP датаграмм, которые необходимо фрагментировать, однако это не было сделано, потому что был установлен флаг "не фрагментировать". | |
ipFragCreates | Counter | Количество IP фрагментов, которые были получены при фрагментации. | |
ipRoutingDiscards | Counter | Количество пунктов маршрутизации, выбранных для уничтожения, даже если они существовали и были верны. |
Группа system довольно проста; она состоит из семи простых переменных (таблиц в этой группе нет). На рисунке 25.16 приведены их имена, типы данных и описания.
Имя | Тип данных | R/W | Описание |
sysDescr | DisplayString | Текстовое описание пункта. | |
sysObjectID | ObjectID | Идентификатор поставщика в поддереве 1.3.6.1.4.1. | |
sysUpTime | TimeTicks | Время в сотых долях секунд с того момента, когда часть системы, отвечающая за управление сетевое, была перестартована. | |
sysContact | DisplayString | · | Имя человека, к которому необходимо обратиться, и как его можно найти. |
sysName | DisplayString | · | Полное имя домена узла (FQDN) . |
sysLocation | DisplayString | · | Физическое расположение узла. |
sysServices | [0..127] | Значение, указывающее на то, какие сервисы предоставляются узлом. Это сумма уровней OSI модели, поддерживаемых узлом. Следующие значения складываются вместе, в зависимости от того, какие сервисы поддерживаются: 0х01 (физический), 0х02 (канальный), 0х04 (сетевой), 0х08 (точка-точка), 0х40 (прикладной). |
На рисунке 25.27 описаны простые переменные группы tcp. Многие из них соответствуют состояниям TCP, которые показаны на рисунке 18.12.
Имя | Тип данных | R/W | Описание |
icmpInMsgs | Counter | Полное количество принятых ICMP сообщений. | |
icmpInErrors | Counter | Количество принятых ICMP сообщений с ошибками (например, ошибочная контрольная сумма ICMP). | |
icmpInDestUnreachs | Counter | Количество принятых ICMP сообщений о недоступности источника. | |
icmpInTimeExcds | Counter | Количество принятых ICMP сообщений об истечении времени. | |
icmpInParmProbs | Counter | Количество принятых ICMP сообщений о проблемах с параметром. | |
icmpInSrcQuenchs | Counter | Количество принятых ICMP сообщений о подавлении источника. | |
icmpInRedirects | Counter | Количество принятых ICMP сообщений о перенаправлении. | |
icmpInEchos | Counter | Количество принятых ICMP сообщений с эхо запросом. | |
icmpInEchoReps | Counter | Количество принятых ICMP сообщений с эхо откликом. | |
icmpInTimestamps | Counter | Количество принятых ICMP сообщений с запросом временной марки. | |
icmpInTimestampReps | Counter | Количество принятых ICMP сообщений с откликом временной марки. | |
icmpInAddrMasks | Counter | Количество принятых ICMP сообщений с запросом маски адреса. | |
icmpInAddrMaskReps | Counter | Количество принятых ICMP сообщений с откликом маски адреса. | |
icmpOutMsgs | Counter | Полное количество исходящих ICMP сообщений. | |
icmpOutErrors | Counter | Количество ICMP сообщений, которые не были отправлены из-за проблем внутри ICMP (переполнение буферов). | |
icmpOutDestUnreachs | Counter | Количество посланных ICMP сообщений о недоступности пункта назначения. | |
icmpOutTimeExcds | Counter | Количество посланных ICMP сообщений об истечении времени. | |
icmpOutParmProbs | Counter | Количество посланных ICMP сообщений о проблемах с параметром. | |
icmpOutSrcQuenchs | Counter | Количество посланных ICMP сообщений о подавлении источника. | |
icmpOutRedirects | Counter | Количество посланных ICMP сообщений о перенаправлении. | |
icmpOutEchos | Counter | Количество посланных ICMP сообщений с эхо запросом. | |
icmpOutEchoReps | Counter | Количество посланных ICMP сообщений с эхо откликом. | |
icmpOutTimestamps | Counter | Количество посланных ICMP сообщений с запросом временной марки. | |
icmpOutTimestampReps | Counter | Количество посланных ICMP сообщений с откликом временной марки. | |
icmpOutAddrMasks | Counter | Количество посланных ICMP сообщений с запросом маски адреса. | |
icmpOutAddrMaskReps | Counter | Количество посланных ICMP сообщений с откликом маски адреса. |
Давайте посмотрим, как TCP обрабатывает ICMP ошибки, которые возвращаются по соединению. В основном TCP обрабатывает следующие ICMP ошибки: подавление источника, хост недоступен и сеть недоступна.
Текущие реализации (производные от Berkeley) обрабатывают эти ICMP ошибки следующим образом: При получении подавления источника, окно переполнения, cwnd, устанавливается в один сегмент, чтобы осуществить медленный старт, однако порог медленного старта, ssthresh, не изменяется, таким образом, окно будет открыто (ограничивается размером окна и временем возврата), пока не возникнет переполнение. Получение ошибки о недоступности хоста или недоступности сети игнорируется, так как эти две ошибки воспринимаются как "кратковременные". Это может произойти из-за того, что промежуточный маршрутизатор вышел из строя, и потребуется несколько минут на то, чтобы протокол маршрутизации установил альтернативный маршрут. В течение этого периода может возникнуть любая из этих двух ICMP ошибок, однако соединение не должно быть разорвано. Вместо этого TCP старается отправить данные, на которые была сгенерирована ошибка, однако, они могут быть отброшены по тайм-ауту. (Обратитесь к рисунку 21.1, на котором показано, что TCP не разрывает соединение в течение 9 минут.) Текущие реализации Berkeley фиксируют возникшие ICMP ошибки, и если соединение разорвано по тайм-ауту, ICMP ошибка транслируется в более понятный код ошибки, который выглядит как "connection timed out" (соединение закрыто по тайм-ауту).
Более ранние реализации BSD некорректно разрывали соединение, когда приходила ICMP ошибка о недоступности хоста или недоступности сети.
Идентификатор объекта это тип данных, указывающий на полномочно названный объект. Под словом "полномочно" мы подразумеваем, что эти идентификаторы не назначаются случайным образом, а назначаются некоторыми организациями, которые несут ответственность за группу идентификаторов.
Идентификатор объекта это последовательность целых десятичных чисел, разделенных точками. Эти целые числа представляют собой древовидную структуру, напоминающую DNS (рисунок 14.1) или файловую систему Unix. В вершине, откуда начинается дерево идентификаторов объектов, существует корень без названия.
На рисунке 25.6 показана структура дерева. Все переменные в MIB начинаются с идентификатора объекта 1.3.6.1.2.1.
У каждого узла в дереве также существует текстовое имя. Имя, соответствующее идентификатору объекта 1.3.6.1.2.1, это iso.org.dod.internet.mgmt.mib. Подобная форма записи имен используется для удобства чтения. Имена переменных MIB используемые при обмене пакетами между менеджером и агентом (рисунок 25.2), это цифровые идентификаторы объектов, начинающиеся с 1.3.6.1.2.1.
Помимо идентификаторов объектов mib, приведенных на рисунке 25.6, мы также привели еще один iso.org.dod.internet.private.enterprises (1.3.5.1.4.1). В этом месте находится MIB различных производителей. В Assigned Numbers RFC приведен список около 400 идентификаторов, зарегистрированных ниже этого узла.
А сейчас мы вернемся к описанию MIB. Опишем следующие группы: system (идентификация системы), if (интерфейсы), at (трансляция адресов), ip, icmp и tcp. Также определены дополнительные группы.
Когда пользовательский агент передает новое почтовое сообщение своему MTA, попытка доставить сообщение обычно осуществляется немедленно. Если доставить сообщение не удалась, MTA поставит сообщение в очередь и повторит попытку позже.
Требования к хостам Host Requirements RFC рекомендует устанавливать первоначальный тайм-аут по крайней мере в 30 минут. Отправитель должен повторять свои попытки по меньшей мере 4-5 дней. Более того, если сбои в доставке происходят часто (получатель вышел из строя или произошла временная потеря сетевого соединения), имеет смысл делать две попытки установить соединение в течение первого часа, когда сообщение находится в очереди.
На рисунке 26.5 показана временная диаграмма для Rlogin соединения от хоста bsdi к серверу svr4. (Мы удалили все связанное с установлением TCP соединения, объявлением окна, а также информацию о типе сервисов.)
Протокол, описанный в предыдущих разделах, можно увидеть в сегментах 1-9. Клиент отправляет один нулевой байт (сегмент 1), за которым следуют три строки (сегмент 3). В этом примере три строки это: rstevens (имя клиента), rstevens (имя на сервере) и ibmpc3/9600 (тип терминала и скорость). Сервер проверяет полномочность этой информации и отвечает нулевым байтом (сегмент 5).
Затем сервер отправляет команду с запросом окна (сегмент 7). Эта команда отправляется с использованием режима срочности TCP. Здесь мы видим реализацию (SVR4), которая использует старую, однако более распространенную интерпретацию, когда указатель срочности указывает на номер последовательности последнего байта срочных данных плюс один. Клиент отвечает 12 байтами данных: 2 байта 0xff, 2 байта s и четыре 16-битных значения.
Следующие четыре сегмента от сервера (10, 12, 14 и 16) это приветствие операционной системы. За ними следует 7-байтное приглашение от shellа: "svr4%" (сегмент 18).
Данные, которые вводит клиент, отправляются по 1 байту за один раз, как показано на рисунке 19.2. Соединение может быть закрыто с любой стороны. Если мы введем команду, которая заставит shell, запущенный на сервере, прекратить свою работу, сервер со своей стороны осуществит активное закрытие. Если мы введем escape последовательность Rlogin клиенту (обычно тильда), за которой следует точка или символ конца файла, клиент осуществит активное закрытие.
Номер порта клиента на рисунке 26.5 равен 1023, это значение находится внутри диапазона, который управляется IANA (глава 1, раздел "Номера портов"). Протокол Rlogin требует, чтобы клиент имел номер порта меньше чем 1024, эти порты называются зарезервированные порты. В Unix системах клиент не может получить зарезервированный порт, если только процесс не имеет привилегии суперпользователя. Это является частью определения полномочий между клиентом и сервером, что позволяет пользователю получить доступ к системе, не вводя пароль. [Stevens 1990] обсуждает эти зарезервированные порты и полномочия, используемые между клиентом и сервером, более подробно.
Во-первых, мы стартовали процесс xscope на том же самом хосте, где находится сервер, при этом xscope слушает запросы на TCP соединение приходящие на порт 6001, а не 6000. Затем мы стартовали клиента на другом хосте и указали дисплей номер 1, а не 0, таким образом, клиент подключается к xscope, а не непосредственно к серверу. Когда запрос на соединение прибывает от клиента, xscope создает TCP соединение на реальный порт сервера 6000 и копирует все между клиентом и сервером, а также предоставляет читаемое описание запросов и откликов. Мы запустим xscope на хосте sun, а клиента xclock на хосте svr4.
svr4 % DISPLAY=sun:1 xclock -digital -update 5
При этом отображаются время и дата в цифровом формате
Thu Sep 9 10:32:55 1993
в окне на хосте sun. Мы указали обновлять время один раз каждые 5 секунд.
Также указана опция -q команды xscope, чтобы получать минимальный вывод. Доступны различные уровни отладки, что позволяет просмотреть все поля в каждом сообщении. Следующий вывод показывает первые три запроса и отклика.
sun % xscope -q
0.00: Client --> 12 bytes
0.02: 152 bytes <-- X11 Server
0.03: Client --> 48 bytes
............REQUEST: CreateGC
............REQUEST: GetProperty
0.20: 396 bytes <-- X11 Server
..............REPLY: GetProperty
0.30: Client --> 8 bytes
0.38: Client --> 20 bytes
............REQUEST: InternAtom
0.43: 32 bytes <-- X11 Server
..............REPLY: InternAtom
Первое сообщение от клиента в момент времени 0,00 и отклик сервера в момент времени 0,02 это стандартное установление соединения между клиентом и сервером. Клиент указывает порядок следования байтов и версию сервера, которую он ожидает. Сервер сообщает о себе различную информацию.
Следующее сообщение в момент времени 0,03 содержит два запроса от клиента. Первый запрос создает на сервере графическое окружение, в котором клиент будет рисовать. Второй получает свойства от сервера (характеристика RESOURCE_MANAGER). Свойства обеспечивают общение между клиентами, обычно между приложением и оконным менеджером. Отклик от сервера размером 396 байт в момент времени 0,20 содержит это свойство.
Следующие два сообщения от клиента в моменты времени 0,30 и 0,38 имеют форму одного запроса, который требует вернуть атом. (Каждое свойство имеет уникальный целый идентификатор, который называется атом.) В момент времени 0.43 сервер отправляет отклик, содержащий атом.
Рассматривать этот пример дальше невозможно без подробного описания того, как работает система X window system, что не является целью нашего повествования. В этом примере мы видим, что перед тем как на дисплее появилось окно, клиент отправил 12 сегментов, содержащих 1668 байт, а сервер отправил 10 сегментов, содержащих 1120 байт. Весь процесс занял 3,17 секунды. С этого момента, каждые 5 секунд, клиент посылает маленький запрос в среднем по 44 байта, которые обновляют окно. Это продолжается до тех пор, пока клиент не будет выключен.