Схема организации процессов 3
Схема организации процессов последовательного мультипротокольного сервера приведена на рис. 14.1. Для приема запросов, поступающих по нескольким транспортным протоколам, применяется один поток выполнения, в котором может быть в любое время открыто не более трех сокетов: один для запросов UDP, другой —для запросов на установление соединения TCP, и еще один (временный) сокет — для обслуживания отдельного соединения TCP.
В последовательном мультипротокольном сервере может быть открыто в любое время не более трех сокетов. Первоначально в нем открывается один сокет для приема входящих дейтаграмм UDP и второй сокет — для приема входящих запросов на установление соединения по протоколу TCP. После поступления дейтаграммы через сокет UDP сервер формирует ответ и передает его клиенту с использованием того же сокета, а после поступления запроса на установление соединения через сокет TCP сервер вызывает функцию accept для получения нового соединения. Функция accept создает третий сокет, предназначенный для обслуживания соединения, а сервер использует этот новый сокет для обмена данными с клиентом. После завершения сеанса обмена данными сервер закрывает третий сокет и переходит в состояние ожидания активизации других двух сокетов.

14.5. Пример мультипротокольного сервера службы DAYTIME
Для демонстрации работы мультипротокольного сервера рассмотрим программу daytimed. Она состоит из одного потока выполнения, который предоставляет службу DAYTIME и по протоколу UDP, и по протоколу TCP.
/* Файл daytimed.с - главная процедура */ tinclude tinclude tinclude tinclude tinclude tinclude tinclude extern int errno; int daytime(char buf[]); int errexit(const char *format, ...); int passiveTCP(const char *servicer int qlen); int passiveUDP(const char *service); tdefine MAX(x, у) ((x)> (у) ? (x) : (y)) tdefine QLEN 32 tdefine LINELEN 128
Программа daytimed принимает необязательный параметр, который позволяет пользователю указать имя службы или номер порта протокола. Если пользователь не задает ни одного параметра, то программа daytimed использует порт службы DAYTIME.
После интерпретации параметров в программе daytimed вызываются процедуры passiveTCP и passiveUDP для создания двух пассивных сокетов, предназначенных для работы по протоколам TCP и UDP. Для обоих сокетов используется одна и та же служба, причем, как и в большинстве служб, для обоих применяется один и тот же номер порта протокола. Эти сокеты можно рассматривать как ведущие: сервер поддерживает их в открытом состоянии неопределенно долгое время и все первоначальные попытки контакта со стороны клиента осуществляются через один из них. В вызове процедуры passiveTCP указывается, что система должна ставить в очередь запросы на установление соединения до тех пор, пока их число не станет равным QLEN.
После создания ведущих сокетов сервер выполняет подготовку к использованию функции select для перехода в состояние ожидания готовности одного или обоих из этих сокетов к вводу/выводу. Во-первых, в нем переменной nfds присваивается значение индекса битовой маски дескриптора старшего из этих двух сокетов, и битовая маска очищается (переменная rfds), после чего сервер входит в бесконечный цикл. При каждом проходе по циклу в нем используется макрокоманда FDJ5ET для построения битовой маски с битами, установленными для дескрипторов, соответствующих двум ведущим сокетам. Затем вызывается функция select для перехода в состояние ожидания активизации ввода через любой из них.
Возврат управления из функции select свидетельствует о том, что готов один или оба из ведущих сокетов. В сервере для проверки сокета TCP, а затем сокета UDP используется макрокоманда FD_ISSET. Сервер должен проверить оба сокета, поскольку может случиться так, что дейтаграмма UDP поступила одновременно с запросом на установление соединения TCP, и в этом случае должны быть готовы оба сокета.
Если готов сокет TCP, это означает, что какой-то клиент инициализировал запрос на установление соединения. Сервер вызывает функцию accept для установления соединения. Эта функция возвращает дескриптор нового, временного сокета, применяемого только для обмена данными через это новое соединение. Сервер вызывает процедуру daytime для формирования ответа, функцию write для передачи ответа через новое соединение, а затем функцию close для разрыва соединения и освобождения ресурсов.
Если готов сокет UDP, это означает, что какой-то клиент прислал дейтаграмму, чтобы запросить ответ от службы DAYTIME. Есть дача? Теперь продажа котельного оборудования осуществляется здесь со скидками! Сервер вызывает функцию recvfrom для чтения входящей дейтаграммы и регистрации адреса оконечной точки клиента. В нем используется процедура daytime для формирования ответа, а затем вызывается функция sendto для передачи ответа клиенту. Поскольку в сервере для всех видов связи используется ведущий сокет UDP, сервер не вызывает функцию close после отправки ответа UDP.