Реализация однопотокового мультисервисного сервера
Хотя такой проект встречается редко, но возможно также обеспечить выполнение всей работы мультисервисного сервера в одном потоке с использованием точно такой же схемы организации процессов, как и в сервере, описанном в главе 13. Вместо создания ведомого процесса для каждого входящего запроса на установление соединения, сервер добавляет сокет для каждого нового соединения к применяемому им в функции select набору сокетов. Бели готов один из ведущих сокетов, сервер вызывает функцию accept; если готов один из ведомых сокетов, сервер вызывает функцию read для получения входящего запроса от клиента, формирует ответ и вызывает функцию write для передачи ответа клиенту. Ведущий процесс/поток обрабатывает входящие запросы на установление соединения, а ведомый процесс/поток обслуживает каждое соединение.
Вызов отдельных программ из мультисервисного сервера
Одним из основных недостатков большинства проектов, описанных выше, является отсутствие модульности: для смены кода поддержки любой отдельно взятой службы требуется перетрансляция всего мультисервисного сервера. Этот недостаток кажется незначительным до тех пор, пока речь не идет о сервере, поддерживающим много служб. Для внесения любого незначительного изменения программист вынужден перетранслировать сервер, остановить существующий и перезапустить его с использованием вновь оттранслированного кода.
Если мультисервисный сервер предоставляет доступ ко многим службам, то велика вероятность того, что хотя бы один клиент будет взаимодействовать с ним в любое конкретное время. Поэтому останов сервера может стать для некоторых клиентов источником проблем. Кроме того, чем больше служб предоставляется сервером, тем выше вероятность того, что в какой-то момент потребуется его доработка.
Проектировщики часто предпочитают разбить крупный, монолитный, мультисервисный сервер на независимые компоненты с использованием отдельно оттранслированных программ для поддержки каждой службы. Применяемый при этом принцип салон свадебных платьев легче понять при рассмотрении параллельного сервера с установлением логического соединения.
Рассмотрим параллельный сервер с установлением логического соединения, который показан на рис. 15.3. Ведущий сервер ожидает поступления запросов на установление соединений через набор ведущих сокетов. После поступления запроса на соединение ведущий сервер вызывает функцию fork для создания ведомого процесса, который будет обслуживать соединение. Сервер должен иметь доступ к коду для всех служб, оттранслированному в целях включения в ведущую программу. На рис. 15.4 показано, как может быть доработан этот проект для разбиения крупного сервера на отдельные части. В сервере используется функция execve для вызова на выполнение отдельной программы, когда возникает необходимость обслужить каждое соединение.
Как показано на этом рисунке, в ведущем сервере применяется функция fork для создания нового ведомого процесса при возникновении необходимости обслужить конкретное соединение. Однако в отличие от описанного ранее проекта, в ведомом процессе вызывается функция execve для замены первоначального кода новой программой, которая обеспечивает все взаимодействие с клиентом.
Поскольку функция execve выполняет выборку новой программы из файла, то проект, описанный выше, позволяет системному администратору в случае необходимости заменить только один файл без перетрансляции мультисервисного сервера, останова главного сервера или его перезапуска. По существу, применение функции execve позволяет отделить программы поддержки каждой службы от кода ведущего сервера, который устанавливает соединения.
Применение в мультисервисном сервере системного вызова execve позволяет отделить код поддержки отдельных служб от кода обслуживания первоначальных запросов клиентов.