Возможно, к этому моменту вам немного наскучило конфигурирование сети. Перейдем к ее использованию на прикладном уровне.

10. Сетевые приложения и службы

В этой главе рассмотрены основы сетевых приложений — клиентов и серверов, работающих в пространстве пользователя, которое располагается на прикладном уровне. Так как этот уровень находится на самом верху стека, ближе всего к конечным пользователям, материал данной главы более доступен, по сравнению с главой 9. Действительно, вы взаимодействуете с такими клиентскими сетевыми приложениями, как браузеры и почтовые клиенты, каждый день.

Для выполнения своей работы сетевые клиенты подключаются к соответству­ющим сетевым серверам. Сетевые серверы Unix включаются в дело различными способами. Серверная команда может либо самостоятельно прослушивать порт, либо через вторичный сервер. В дополнение к этому у серверов нет общей базы данных конфигурации и широкого набора функций. Большинство серверов использует файл конфигурации для контроля своего поведения (хотя для такого файла и нет установленного формата), а многие применяют также системную службу syslog для записи уведомлений. Мы рассмотрим некоторые распространенные серверы, а также ин­струменты, которые помогут вам понять и отладить работу сервера.

Сетевые клиенты используют протоколы и интерфейсы транспортного уровня операционной системы, поэтому важно понимать основы транспортных уровней TCP и UDP. Начнем рассмотрение сетевых приложений, поэкспериментировав с сетевым клиентом, который использует протокол TCP.

10.1. Основные понятия о службах

Службы TCP являются одними из самых простых для понимания, поскольку они построены на несложных, непрерывных двухсторонних потоках данных. Вероятно, лучший способ увидеть, как они работают, — «пообщаться» с веб-сервером напрямую через TCP-порт 80 и получить представление о том, как данные перемещаются через это соединение. Запустите, например, такую команду для подключения к веб-серверу:

$ telnet www.wikipedia.org 80

Вы должны увидеть в ответ нечто подобное:

Trying some address...

Connected to www.wikipedia.org.

Escape character is '^]'.

Теперь введите:

GET / HTTP/1.0

Нажмите клавишу Enter дважды. Сервер должен отправить в виде ответа некоторое количество HTML-текста, а затем разорвать соединение.

Это упражнение говорит нам о том, что:

• на удаленном хосте есть процесс веб-сервера, прослушивающий TCP-порт 80;

• клиентом, который инициировал соединение, являлась команда telnet.

примечание

Команда telnet изначально была предназначена для осуществления входа на удаленные хосты. Хотя вход на удаленный сервер с помощью команды telnet без использования технологии Kerberos совершенно не защищен (как вы увидите далее), клиент telnet может быть полезен для отладки удаленных служб. Команда telnet не работает с протоколом UDP или любым транспортным уровнем, отличным от TCP. Если вы ищете сетевой клиент общего назначения, попробуйте команду netcat, описанную в подразделе 10.5.3.

В приведенном выше примере вы вручную выполнили взаимодействие с веб-сервером в сети с помощью команды telnet, использовав протокол HTTP (Hypertext Transfer Protocol, протокол передачи гипертекста) прикладного уровня. Хотя в обычных условиях вы воспользовались бы браузером для установления подобного соединения, немного отойдем от команды telnet и применим команду, которая знает, как «говорить» с прикладным уровнем HTTP. Мы используем утилиту curl со специальным параметром, чтобы записать подробности ее взаимодействия:

$ curl —trace-ascii trace_file http://www.wikipedia.org/

примечание

В вашей версии ОС может не оказаться встроенной утилиты curl, но, если она понадобится, ее установка не должна вызвать трудностей.

Вы получите обширный отчет в формате HTML. Проигнорируйте его (или перенаправьте в устройство /dev/null) и вместо этого посмотрите только что созданный файл trace_file. При условии, что соединение оказалось успешным, первая часть этого файла, в том месте, где команда curl пытается установить TCP-соединение с сервером, должна выглядеть так:

== Info: About to connect() to www.wikipedia.org port 80 (#0)

== Info:   Trying 10.80.154.224... == Info: connected

Все, что вы видели до сих пор, происходит на транспортном уровне или под ним. Однако, если это соединение оказывается успешным, команда curl пытается отправить запрос («заголовок»); именно в этот момент в дело вступает прикладной уровень:

=> Send header, 167 bytes (0xa7)

0000: GET / HTTP/1.1

0010: User-Agent: curl/7.22.0 (i686-pc-linux-gnu) libcurl/7.22.0 OpenS

0050: SL/1.0.1 zlib/1.2.3.4 libidn/1.23 librtmp/2.3

007f: Host: www.wikipedia.org

0098: Accept: */*

00a5:

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

Видно, что команда curl начинает работу с отправки запроса GET серверу (как вы это делали с помощью команды telnet), за которым следует дополнительная информация для сервера и пустая строка. Далее сервер отправляет ответ, первый с собственным заголовком, который выделен здесь жирным шрифтом:

<= Recv header, 17 bytes (0x11)

0000: HTTP/1.1 200 OK

<= Recv header, 16 bytes (0x10)

0000: Server: Apache

<= Recv header, 42 bytes (0x2a)

0000: X-Powered-By: PHP/5.3.10-1ubuntu3.9+wmf1

snip

Во многом подобно предыдущему выводу, здесь строки <= являются отладочными, а числа 0000:, с которых они начинаются, сообщают вам смещения.

Заголовок в ответе сервера может оказаться достаточно длинным, но в определенный момент сервер переходит от передачи заголовков к отправке запрашива­емого документа, например, так:

<= Recv header, 55 bytes (0x37)

0000: X-Cache: cp1055 hit (16), cp1054 frontend hit (22384)

<= Recv header, 2 bytes (0x2)

0000:

<= Recv data, 877 bytes (0x36d)

0000: 008000

0008: <!DOCTYPE html>.<html lang="mul" dir="ltr">.<head>.<!— Sysops:

snip

Этот вывод иллюстрирует также важное свойство прикладного уровня. Даже если отладочный вывод содержит Recv header и Recv data, подразумевая за ними два различных типа сообщений от сервера, нет никаких различий ни в том, как команда curl общается с операционной системой для извлечения этих сообщений, ни в том, как операционная система обращается с ними, ни в том, как сеть обрабатывает лежащие в их основе пакеты. Различие содержится полностью внутри приложения curl в пространстве пользователя. Команда curl знает о том, что она получает заголовки, пока ей не встретится пустая строка (двухбайтный фрагмент в середине), которая сигнализирует об окончании HTTP-заголовков, тогда команда интерпретирует все, что последует далее, как запрашиваемый документ.

Это же верно и для сервера, отправляющего данные. При отправке ответа сервер не делает различий между заголовком и данными документа, отправленными операционной системе; различия появляются внутри серверной программы в пространстве пользователя.

10.2. Сетевые серверы

Большинство сетевых серверов подобно другим демонам системы, таким как cron, за исключением того, что они взаимодействуют с сетевыми портами. В самом деле, вспомните демон syslogd, описанный в главе 7: он принимает пакеты UDP в сетевом порте 514, когда запущен с параметром -r.