Большинство сетевых приложений можно разделить на две группы: клиенты и серверы. Связь между ними демонстрирует рис. 1.1.
Рис. 1.1. Сетевое приложение: клиент и сервер
Можно привести множество примеров клиентов и серверов, с которыми, вероятно, читатель знаком: web-браузер (клиент), соединяющийся с web-сервером; клиент FTP, получающий файлы с сервера FTP; клиент Telnet, используемый нами для того, чтобы войти на удаленный узел через сервер Telnet на этом удаленном узле.
Обычно за один сеанс клиенты устанавливают соединение с одним сервером, хотя если говорить о web-браузере, мы можем соединиться со множеством различных web-серверов, скажем, в течение 10 минут. Однако с точки зрения сервера нет ничего удивительного в том, что в любой момент времени он соединяется
Рис. 1.2. Сервер, обслуживающий одновременно множество клиентов
со множеством клиентов (рис. 1.2). Далее в этой главе будут рассмотрены различные возможности взаимодействия сервера одновременно со множеством клиентов.
Взаимодействие клиентского и серверного приложений невозможно без сетевых протоколов. В этой книге мы сосредоточимся на наборе (стеке) протоколов TCP/IP, называемом также набором протоколов Интернета. Так, например, клиенты и серверы Web устанавливают соединения, используя протокол TCP. TCP, в свою очередь, использует протокол IP, а протокол IP устанавливает соединение с тем или иным протоколом канального уровня. Например, если и клиент, и сервер находятся в одной сети Ethernet, взаимодействие между ними будет соответствовать показанному на рис. 1.3.
Рис. 1.3. Клиент и сервер в сети Ethernet, соединеннные по протоколу TCP
Несмотря на то что клиент и сервер устанавливают соединение с использованием протокола уровня приложений, транспортные уровни устанавливают соединение, используя TCP, и т. д., нужно отметить, что действительный поток информации между клиентом и сервером идет вниз по стеку протоколов на стороне клиента, затем по сети и, наконец, вверх по стеку протоколов на стороне сервера.
Отметим также, что клиент и сервер являются типично пользовательскими процессами, в то время как TCP и протоколы IP обычно являются частью стека протоколов внутри ядра. На рис. 1.3 мы выделили четыре уровня процессов.
Мы будем обсуждать не только протоколы TCP и IP. Некоторые клиенты и серверы вместо протокола TCP используют UDP, и оба эти протокола более подробно обсуждаются в главе 2. Употребляя термин IP, мы подразумеваем последнюю официальную версию этого протокола — IPv4. Новая версия этого протокола, IP версии 6, была разработана в середине 90-х и, возможно, со временем заменит протокол IPv4. Начальные реализации протокола IPv6 были доступны на момент написания этой книги, и в тексте описана разработка сетевых приложений как под IPv4, так и под IPv6. В приложении A приводится сравнение протоколов IPv4 и IPv6 с другими протоколами, с которыми вы встретитесь.
Вовсе не обязательно, чтобы клиент и сервер находились, как показано на рис. 1.3, в одной и той же локальной сети (local area network, LAN). Напротив, клиент и сервер могут относиться к разным локальным сетям (рис. 1.4), при этом обе локальных сети должны быть соединены в глобальной сети (wide-area network, WAN) с использованием маршрутизаторов.
Рис. 1.4. Клиент и сервер в различных локальных сетях, соединенных через глобальную сеть
Маршрутизаторы — это блоки, из которых строится глобальная сеть. На сегодняшний день наибольшей глобальной сетью является Интернет, хотя многие компании создают свои собственные глобальные сети, и эти частные сети могут быть, а могут и не быть подключены к Интернету.
Оставшаяся часть этой главы представляет собой обзор различных тем, которые более подробно раскрываются далее по тексту книги. Мы начнем с полного, хотя и простого примера TCP-клиента, демонстрирующего вызовы многих функций и понятия, с которыми мы встретимся в книге. Клиент работает только с протоколом IP версии 4. Мы покажем изменения, необходимые для работы с протоколом IP версии 6. Разумнее всего создавать не зависящие от протокола клиенты и серверы, и это решение будет рассмотрено нами в главе 11. В этой главе также показан пример сервера TCP, работающего с нашим клиентом.
Чтобы упростить написанный нами код, мы определяем наши собственные функции-обертки (wrapper functions) для большинства системных функций, которые будем вызывать. В большинстве случаев мы будем использовать функции-обертки для поиска ошибок, вывода соответствующих сообщений и завершения работы при обнаружении ошибки.
Кроме того, в этой главе мы подробно расскажем о сети, использовавшейся для тестирования примеров из книги, приведем имена узлов, их IP-адреса и названия операционных систем, под управлением которых они работают.
В настоящее время нельзя говорить о Unix, не упомянув Posix — стандарт, принятый большинством производителей. Мы опишем историю стандарта Posix и расскажем, каким образом он определяет API, рассматриваемые в этой книге наряду с другими конкурирующими стандартами.