Марк Митчелл - Программирование для Linux. Профессиональный подход
- Название:Программирование для Linux. Профессиональный подход
- Автор:
- Жанр:
- Издательство:Вильямс
- Год:2002
- Город:Москва
- ISBN:5-8459-0243-6
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Марк Митчелл - Программирование для Linux. Профессиональный подход краткое содержание
Данная книга в основном посвящена программированию в среде GNU/Linux. Авторы применяют обучающий подход, последовательно излагая самые важные концепции и методики использования расширенных возможностей системы GNU/Linux в прикладных программах. Читатели научатся писать программы, к интерфейсу которых привыкли пользователи Linux; освоят такие технологии, как многозадачность, многопотоковое программирование, межзадачное взаимодействие и взаимодействие с аппаратными устройствами; смогут улучшить свои программы, сделав их быстрее, надежнее и безопаснее; поймут особенности системы GNU/Linux, ее ограничения, дополнительные возможности и специфические соглашения.
Книга предназначена для программистов, уже знакомых с языком С и имеющих базовый опыт работы в GNU/Linux.
Программирование для Linux. Профессиональный подход - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
/* Все правильно. */
module_dir = strdup(optarg);
}
break;
case 'p':
/* Пользователь ввел -p или --port. */
{
long value;
char* end;
value = strtol(optarg, &end, 10);
if (*end != '\0')
/* В номере порта указаны не только цифры. */
print_usage(1);
/* Преобразуем номер порта в число с сетевым (обратным)
порядком следования байтов. */
port = (uint16_t)htons(value);
}
break;
case 'v':
/* Пользователь ввел -v или --verbose. */
verbose = 1;
break;
case '?':
/* Пользователь ввел непонятную опцию. */
print_usage(1);
case -1:
/* Обработка опций завершена. */
break;
default:
abort();
}
} while (next_option != -1);
/* Программа не принимает никаких дополнительных аргументов.
Если они есть, выдается сообщение об ошибке. */
if (optind != argc)
print_usage(1);
/* Отображение имени каталога, если программа работает в режиме
развернутых сообщений. */
if (verbose)
printf("modules will be loaded from %s\n", module_dir);
/* Запуск сервера. */
server_run(local_address, port);
return 0;
}
Файл main.c
содержит следующие функции.
■ Функция getopt_long()
(см. раздел 21.3, "Функция getopt_long()") вызывается для анализа опций командной строки. Опции могут задаваться в двух форматах: длинном и коротком. Описание длинных опций приведено в массиве long_options
, а коротких — в массиве short_options
.
По умолчанию серверный порт имеет номер 0, а локальный адрес задан в виде константы INADDR_ANY
. Эти установки можно переопределить с помощью опций --port
( -p
) и - -address
( -a
) соответственно. Если пользователь ввел адрес, вызывается библиотечная функция gethostbyname()
, преобразующая его в числовой Internet-адрес. [38] При необходимости функция gethostbyname() осуществляет поиск имен в DNS.
По умолчанию серверные модули загружаются из каталога, где находится исполняемый файл. Этот каталог определяется с помощью функции get_self_executable_directory()
. Данную установку можно переопределить с помощью опции --module
( -m
). В таком случае проверяется, является ли указанный каталог доступным.
По умолчанию развернутые сообщения не отображаются, если не указать опцию --verbose
( -v
).
■ Если пользователь ввел опцию --help
( -h
) или указал неправильную опцию, вызывается функция print_usage()
, которая отображает сообщение о правильном использовании программы и завершает работу.
11.3. Модули
В дополнение к основной программе созданы четыре модуля, в которых реализованы функции сервера. Чтобы создать собственный модуль, достаточно определить функцию module_generate()
, которая будет возвращать HTML-код.
11.3.1. Отображение текущего времени
Модуль time.so
(исходный текст приведен в листинге 11.6) генерирует простую страницу, где отображается текущее время на сервере. В функции module_generate()
вызывается функция gettimeofday()
, возвращающая значение текущего времени (см. раздел 8.7, "Функция gettimeofday(): системные часы"), после чего функции localtime()
и strftime()
преобразуют это значение в текстовый формат. Полученная строка встраивается в шаблон HTML-страницы page_template.
#include
#include
#include
#include
#include "server.h"
/* шаблон HTML-страницы, генерируемой данным модулем. */
static char* page_template =
"\n"
"
\n"
"
\n"
" \n"
"
\n"
"
The current time is %s
\n"
"
\n"
"
\n";
void module_generate(int fd) {
struct timeval tv;
struct tm* ptm;
char time_string[40];
FILE* fp;
/* Определение времени суток и заполнение структуры типа tm. */
gettimeofday(&tv, NULL);
ptm = localtime(&tv.tv_sec);
/* Получение строкового представления времени с точностью
до секунды. */
strftime(time_string, sizeof(time_string), "%H:%M:%S", ptm);
/* Создание файлового потока, соответствующего дескриптору
клиентского сокета. */
fp = fdopen(fd, "w");
assert(fp != NULL);
/* Запись HTML-страницы. */
fprintf(fp, page_template, time_string);
/* Очистка буфера потока */
fflush(fp);
}
Для удобства в этом модуле используются стандартные библиотечные функции ввода-вывода. Функция fdopen()
возвращает указатель потока ( FILE*
), соответствующий дескриптору клиентского сокета (подробнее об этом рассказывается в приложении Б, "Низкоуровневый ввод-вывод"). Для отправки страницы клиенту вызывается обычная функция fprintf()
, а функция fflush()
предотвращает потерю данных в случае закрытия сокета.
HTML-страница, возвращаемая модулем time.so
, содержит в заголовке тэг
11.3.2. Отображение версии Linux
Модуль issue.so
(исходный текст приведен в листинге 11.7) выводит информацию о дистрибутиве Linux, с которым работает сервер. Традиционно эта информация хранится в файле /etc/issue
. Модель посылает клиенту Web-страницу с содержимым файла, заключенным в тэге
#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;
/* Запись начала страницы */
Интервал:
Закладка: