Мультисервисные и мультипротокольные проекты
Хотя и принято считать, что мультисервисный сервер должен обязательно быть сервером либо с установлением, либо без установления логического соединения, возможен также мультипротокольный проект. Как описано в главе 14, мультипротокольный проект позволяет обслуживать в одном потоке сервера и сокет UDP, и сокет TCP для одной и той же службы. С другой стороны, мультисервисный сервер может обслуживать сокеты UDP и TCP только для некоторых или одновременно для всех служб, которые он предлагает.
Специалисты по сетям для обозначения мультисервисного мультипротокольного сервера часто используют термин суперсервер. В принципе, суперсервер функционирует во многом аналогично обычному мультисервисному серверу.
Первоначально сервер открывает один или два ведущих сокета для каждой из предоставляемых им служб. Ведущие сокеты для каждой конкретной службы соответствуют транспортному протоколу без установления логического соединения (UDP) или транспортному протоколу с установлением логического соединения (TCP). В сервере используется функция select для перехода в состояние ожидания готовности к работе любого сокета. Если готов сокет UDP, сервер вызывает процедуру, которая считывает следующий запрос (дейтаграмму) из сокета, формирует ответ и передает его клиенту. Если готов сокет TCP, сервер вызывает процедуру, которая получает с помощью функции accept, вызванной с этим сокетом, новое соединение и обслуживает его. Сервер может сам обслуживать соединение, и в этом случае он является последовательным, или создавать новый процесс для обслуживания соединения, и тогда он считается параллельным.
15.9. Пример с мультисервисным сервером
Мультисервисный сервер, представленный в файле superd.c, расширяет реализацию сервера, которая описана в главе 14. После инициализации структур данных и открытия сокетов для каждой из предоставляемых служб, главная процедура входит в бесконечный цикл. При каждом проходе по циклу вызывается функция select для перехода в состояние ожидания готовности одного из сокетов. Возврат из функции select происходит после поступления запроса.
После возврата управления из функции select сервер перебирает в цикле все возможные дескрипторы сокетов и использует макрокоманду FD_ISSET для проверки готовности дескриптора. Найдя готовый к работе дескриптор сокета, сервер вызывает функцию для обработки содержащегося в сокете запроса. Для этого в сервере вначале используется массив fd2sv для установления соответствия между номером дескриптора и записью в массиве svent.
Каждая запись в массиве svent содержит структуру типа service, которая устанавливает соответствие между дескриптором сокета и службой. Поле sv_func содержит адрес функции, предназначенной для поддержки службы. После установления соответствия между дескриптором и записью массива svent программа вызывает выбранную функцию. Для обслуживания сокета UDP сервер вызывает обработчик службы непосредственно, а для обслуживания сокета TCP сервер вызывает обработчик службы косвенно, через процедуру doTCP.
Для служб TCP требуется дополнительная процедура, поскольку сокет TCP в сервере с установлением логического соединения соответствует ведущему сокету. Переход в состояние готовности такого сокета означает, что в него поступил запрос на установление соединения. В сервере для обслуживания соединения должен быть создан новый процесс. Поэтому в процедуре doTCP вызывается функция accept для получения нового соединения. В ней затем вызывается функция fork для создания нового ведомого процесса. После закрытия лишних дескрипторов файлов в процедуре doTCP вызывается функция обработчика службы (svjiunc). После возврата управления из этой функции поддержки службы ведомый процесс завершается.
/* Файл superd.c - главная процедура */ tdefine _USE_BSD tinclude tinclude tinclude tinclude tinclude
Суперсервер, приведенный в данном примере, предоставляет доступ к четырем службам: ECHO, CHARGEN, DAYTIME и TIME. Все службы, кроме CHARGEN, были описаны в качестве примеров в предыдущих главах. Служба CHARGEN используется программистами для проверки клиентского программного обеспечения. Сразу после установления клиентом соединения с сервером CHARGEN сервер формирует бесконечную последовательность символов и передает их клиенту.
Код большинства отдельных функций должен быть уже знаком читателю; он был взят из примеров с серверами, которые рассматривались в предыдущих главах. Код поддержки службы CHARGEN приведен в процедуре TCPchargend; он является несложным. Процедура состоит из цикла, в котором повторно формируется буфер, заполненный символами ASCII, а затем для передачи содержимого буфера клиенту вызывается функция write.