Искусство программирования для Unix
Шрифт:
Сокеты (sockets) были разработаны в BSD-ветви Unix как способ инкапсуляции доступа к сетям данных. Две программы, осуществляющие обмен данными через сокет, обычно используют двунаправленный поток байтов (существуют и другие режимы сокетов и методы передачи, но они имеют только второстепенное значение). Байтовый поток является как последовательным (т.е. все байты будут приняты в том же порядке, в котором они были отправлены), так и надежным (пользователи сокетов могут быть уверены, что базовая сеть в целях обеспечения гарантированной доставки осуществляет обнаружение ошибок и повтор передачи). Дескрипторы сокетов, полученные однажды, работают, по существу, подобно дескрипторам файлов.
Сокеты
принято в прошлом. Ответы для локального ввода/вывода — "да" или "нет". Ответы для ввода/вывода сокета — "да", "нет", "возможно". И ничто не может гарантировать доставку — удаленная машина могла быть уничтожена кометой.
Кен Арнольд.
Во время создания сокета задается семейство протоколов, которое указывает сетевому уровню, как интерпретировать имя данного сокета. Сокеты обычно в связи с Internet рассматриваются как способ передачи данных между программами, запущенными на различных узлах. Таковым является семейство сокетов AF_INET, в котором адреса интерпретируются как пары "адрес узла-номер службы". Однако семейство протоколов AF_UNIX (также известное как AF_LOCAL) поддерживает ту же абстракцию сокетов для обмена данными между двумя процессами на одной машине (имена интерпретируются как места расположения специальных файлов аналогично двунаправленным именованным каналам). Например, в клиентских программах и серверах, использующих систему X Window, для обмена данными обычно применяются сокеты AF_LOCAL.
Все современные Unix-системы поддерживают BSD-стиль сокетов, и в вопросе конструкции они обычно являются верным решением при использовании для двунаправленного IPC-взаимодействия не зависимо от того, где расположены взаимодействующие процессы. Желание повысить производительность может подтолкнуть разработчика к применению общей памяти, временных файлов или других технических приемов, которые вносят более строгие предположения о расположении, но в современных условиях лучше всего предполагать, что разрабатываемый код в будущем потребует расширения в целях поддержки распределенных операций. Еще более важно то, что данные локальные предположения могут означать, что внутренние блоки системы смешиваются больше, чем это должно быть в случае хорошей конструкции. Разделение адресных пространств, навязанное сокетами, является полезной особенностью, а не ошибкой.
Для того чтобы изящно, в духе Unix использовать сокеты, следует начинать с разработки используемого между ними протокола прикладного уровня, т.е. набора запросов и ответов, лаконично выражающего семантику данных, которыми будут обмениваться программы. Некоторые основные вопросы в проектировании протоколов прикладного уровня уже рассматривались в главе 5.
Сокеты поддерживаются во всех последних операционных системах семейства Unix, Microsoft Windows, а также в классической MacOS.
7.2.6.5.1. Учебный пример: PostgreSQL
PostgreSQL — программа с открытым исходным кодом для обработки баз данных. Если бы она была реализована как монолит, то это была бы одна программа с интерактивным интерфейсом, манипулирующая файлами баз данных непосредственно на диске. Интерфейс был бы неразрывно связанным с реализацией, и два экземпляра программы, пытающиеся
одновременной манипулировать одной базой данных, создавали бы серьезные проблемы конфликтов и блокировок.Вместо этого пакет PostgreSQL включает в себя сервер, который называется postmaster, и по крайней мере 3 клиентских приложения. В машине в фоновом режиме запускается один серверный процесс postmaster. Данный процесс имеет исключительный доступ к файлам базы данных. Он принимает запросы на мини-языке SQL-запросов посредством TCP/IP-сокетов, а также возвращает ответы в текстовом формате. Запущенный пользователем PostgreSQL-клиент открывает сеанс связи с сервером postmaster и выполняет с ним SQL-транзакции. Одновременно сервер способен обрабатывать несколько клиентских сеансов, а их запросы последовательно располагаются так, что не пересекаются друг с другом.
Поскольку клиентская и серверная части обособлены, серверу не требуется выполнять других задач, кроме интерпретации SQL-запросов от клиента и отправки SQL-отчетов в обратном направлении. С другой стороны, клиентам не требуется иметь какую-либо информацию о том, как хранится база данных. Клиенты могут быть специализированы для решения различных задач и иметь разные пользовательские интерфейсы.
Подобная организация весьма типична для баз данных в операционной системе Unix — настолько типична, что часто возможно сочетать и подбирать SQL-клиенты и SQL-серверы. Проблемы взаимодействия связаны с номером ТСРДР-порта SQL-сервера, а также с тем, поддерживают ли клиент и сервер один и тот же диалект SQL.
7.2.6.5.2. Учебный пример: Freeciv
В главе 6 игра Freeciv была представлена в качестве иллюстрации прозрачного формата данных. Однако более важным для поддержки игры с множеством участников является разделение кода на клиентскую и серверную части. Freeciv является характерным примером программы, в которой приложение должно быть распределено в сети и поддерживает связь через ТСР/1Р-сокеты.
Состояние запущенной игры Freeciv обслуживается серверным процессом, ядром игры. Игроки запускают GUI-клиенты, которые обмениваются информацией и командами с сервером посредством пакетного протокола. Вся игровая логика обрабатывается на сервере. Детали GUI-интерфейса обрабатываются клиентом. Различные клиенты поддерживают разные стили интерфейсов.
Организация данной игры весьма типична для сетевых игр с множеством участников. Пакетный протокол использует в качестве транспорта протокол TCP/IP, поэтому один сервер способен поддерживать клиентов, запущенных на различных узлах в Internet. В других играх, более похожих на симуляторы реального времени (особенно боевые игры от первого лица), используется протокол дейтаграмм Internet (UDP), и низкая задержка достигается за счет некоторой ненадежности доставки какого-либо определенного пакета. В таких играх пользователи, как правило, непрерывно выполняют управляющие действия, поэтому единичные потери пакетов допустимы, а задержка фатальна.
7.2.6.6. Общая память
Тогда как два процесса, использующие для информационного обмена сокеты, могут выполняться на различных машинах (и в действительности могут быть разделены Internet-соединением, "огибающим" половину планеты), общая память (shared memory) требует, чтобы поставщики и потребители данных одновременно находились в памяти одного компьютера. Однако, если процессы, обменивающиеся данными, могут получить доступ к одной физической памяти, то общая память будет самым быстрым способом передачи информации между ними.