■ Программа не претендует на полную совместимость со спецификациями HTML (http://www.w3.org/MarkUp/). Она генерирует простые HTML-страницы, которые могут обрабатываться популярными Web-броузерами.
■ Сервер не настроен на максимальную производительность или минимальное потребление ресурсов. В частности, мы сознательно опустили код сетевой настройки, обычно имеющийся у Web-сервера. Рассмотрение этой темы выходит за рамки нашей книги.
■ Мы не пытаемся регулировать объем ресурсов (число процессов, объем используемой памяти), потребляемых сервером или его модулями. Многие многозадачные Web-серверы обслуживают запросы посредством фиксированного пула процессов, а не создают новый дочерний процесс для каждого соединения.
■ Всякий раз, когда поступает запрос, сервер загружает библиотеку с модулем, которая немедленно выгружается по окончании обработки запроса. Эффективнее было бы кэшировать загруженные модули.
Протокол HTTP (Hypertext Transport Protocol) используется для организации взаимодействия Web-клиентов и серверов. Клиент подключается к серверу, устанавливая соединение с заранее известным портом (обычно его номер — 80). Запросы и заголовки HTTP представляются в виде обычного текста.
Подключившись к серверу, клиент посылает запрос. Типичный запрос выглядит так: GET /page HTTP/1.0. Метод GET означает запрос на получение Web-страницы. Второй элемент — это путь к странице. В третьем элементе указан протокол и его версия. В последующих строках содержатся поля заголовка отформатированные наподобие заголовков почтовых сообщений. В них приведена дополнительная информация о клиенте. Заголовок оканчивается пустой строкой.
В ответ сервер сообщает результат обработки запроса. Типичный ответ таков: HTTP/1.0 200 OK. Первый элемент — это версия протокола. В следующих двух элементах описан результат. В данном случае код 200 означает успешное выполнение запроса. Далее идут поля заголовка, который, оканчивается пустой строкой. После заголовка сервер может передать произвольные данные.
Обычно сервер возвращает HTML-код Web-страницы. В рассматриваемом примера в заголовке ответа будет указано следующее: Content-type: text/html.
Спецификацию протокола HTTP можно получить по адресу http://www.w3.org/Protocols.
11.2. Реализация
Во всех более-менее сложных C-программах требуется тщательно продумать организацию, чтобы сохранить модульность и обеспечить удобство сопровождения. Наша демонстрационная программа разделена на четыре главных исходных файла.
В каждом исходном файле экспортируются функции и переменные, используемые в других частях программы. Для простоты все они объявлены в одном файле заголовков: server.h (листинг 11.1). Функции, применяемые в рамках только одного модуля, объявлены со спецификатором static и не включены в файл server.h.
#ifndef SERVER_H
#define SERVER_H
#include <netinet/in.h>
#include <sys/types.h>
/*** Символические константы файла common.c. ********************/
/* Имя программы. */
extern const char* program_name;
/* Если не равна нулю, отображаются развернутые сообщения. */
extern int verbose;
/* Напоминает функцию malloc(), не прерывает работу программы,
если выделить память не удалось. */
extern void* xmalloc(size_t size);
/* Напоминает функцию realloc(), но прерывает работу программы,
если выделить память не удалось */
extern void* xrealloc(void* ptr, size_t size);
/* Напоминает функцию strdup(), но прерывает работу программы,
если выделить память не удалось. */
extern char* xstrdup(const char* s);
/* Выводит сообщение об ошибке заданного системного вызова
и завершает работу программы. */
extern void system_error(const char* operation);
/* Выводит сообщение об ошибке и завершает работу программы. */
extern void error(const char* cause, const char* message);
/* Возвращает имя каталога, содержащего исполняемый файл
программы. Поскольку возвращается указатель на область памяти,
вызывающая подпрограмма должна удалить ее с помощью
функции free(). В случае неудачи выполнение программы
завершается. */