клиентского сокета. */
fp = fdopen(fd, "w");
assert(fp != NULL);
/* Запись HTML-страницы. */
fprintf(fp, page_template, time_string);
/* Очистка буфера потока */
fflush(fp);
}
Для удобства в этом модуле используются стандартные библиотечные функции ввода-вывода. Функция fdopen()
возвращает указатель потока ( FILE*
), соответствующий дескриптору клиентского сокета (подробнее об этом рассказывается в приложении Б, "Низкоуровневый ввод-вывод"). Для отправки страницы клиенту вызывается обычная функция fprintf()
, а функция fflush()
предотвращает потерю данных в случае закрытия сокета.
HTML-страница, возвращаемая модулем time.so
, содержит в заголовке тэг
, который служит клиенту указанием перезагружать страницу каждые 5 секунд. Благодаря этому клиент всегда будет знать точное время.
11.3.2. Отображение версии Linux
Модуль issue.so
(исходный текст приведен в листинге 11.7) выводит информацию о дистрибутиве Linux, с которым работает сервер. Традиционно эта информация хранится в файле /etc/issue
. Модель посылает клиенту Web-страницу с содержимым файла, заключенным в тэге
.
Листинг 11.7. ( issue.c ) Серверный модуль, отображающий информацию о дистрибутиве Linux
#include
#include
#include
#include
#include
#include
#include "server.h"
/* HTML-код начала генерируемой страницы. */
static char* page_start =
"\n"
"
\n"
"
\n";
/* HTML-код конца генерируемой страницы. */
static char* page_end =
"
\n"
"
\n"
"
\n";
/* HTML-код страницы, сообщающей о том, что
при открытии файла /etc/issue произошла ошибка. */
static char* error_page =
"\n"
"
\n"
"
Error: Could not open /etc/issue.
\n"
"
\n"
"
\n";
/* Сообщение об ошибке. */
static char* error_message =
"Error reading /etc/issue.";
void module_generate(int fd) {
int input_fd;
struct stat file_info;
int rval;
/* Открытие файла /etc/issue */
input_fd = open("/etc/issue", O_RDONLY);
if (input_fd == -1)
system_error("open");
/* Получение информации о файле. */
rval = fstat(input_fd, &file_info);
if (rval == -1)
/* не удалось открыть файл или прочитать данные из него. */
write(fd, error_page, strlen(error_page));
else {
int rval;
off_t offset = 0;
/* Запись начала страницы */
write(fd, page_start, strlen(page_start));
/* Копирование данных из файла /etc/issue
в клиентский сокет. */
rval = sendfile(fd, input_fd, &offset, file_info.st_size);
if (rval == -1)
/* При отправке файла /etc/issue произошла ошибка.
Выводим соответствующее сообщение. */
write(fd, error_message, strlen(error_message));
/* Конец страницы. */
write(fd, page_end, strlen(page_end));
}
close(input_fd);
}
Сначала модуль пытается открыть файл /etc/issue
. Если это не удалось, клиенту возвращается сообщение об ошибке. В противном случае посылается начальный код HTML-страницы, содержащийся в переменной page_start
, затем — содержимое файла /etc/issue
(это делается с помощью функции sendfile()
, о которой рассказывалось в разделе 8.12. "Функция sendfile(): быстрая передача данных") и, наконец конечный код HTML-страницы, содержащийся в переменной page_end
.
Этот модуль можно легко настроить на отправку любого другого файла. Если файл содержит HTML-страницу, переменные page_start
и page_end
будут не нужны.
11.3.3. Отображение объема свободного дискового пространства
Модуль diskfree.so
(исходный текст приведен в листинге 11.8) генерирует страницу с информацией о свободном дисковом пространстве в файловых системах, смонтированных на серверном компьютере. Эта информация берется из выходных данных команды df -h
. Как и в модуле issue.so
, выходные данные заключаются в тэги
.
Листинг 11.8. ( diskfree.c ) Серверный модуль, отображающий информацию о свободном дисковом пространстве
#include
#include
#include
#include
#include "server.h"
/* HTML-код начала генерируемой страницы. */
static char* page_start =
"\n"
"
\n"
"
\n";
/* HTML-код конца генерируемой страницы. */
static char* page_end =
"
\n"
"
\n"
"
\n";
void module_generate(int fd) {
pid_t child_pid;
int rval;
Читать дальше