· /proc/ide – каталог, содержащий файлы, которые описывают устройства, подключенные к шинам IDE и SCSI.
· /proc/net/dev – содержит информацию о сетевых платах и их конфигурации.
Информация о конфигурации и состоянии ядра системы представлена в следующих файлах:
· /proc/version – содержит строку, описывающую номер версии и модификации ядра; в нее также включена дополнительная информация: имя пользователя, осуществившего компиляцию, дата компиляции и версия компилятора;
· /proc/meminfo – хранит сведения об использовании системной памяти; указываются данные как о физической памяти, так и об области подкачки;
· /proc/modules – полный список установленных модулей ядра в текстовом виде.
Информация о файловых системах представлена следующими файлами:
· /proc/filesystems – список файловых систем, поддерживаемых ядром;
· /proc/mounts – содержит перечень смонтированных файловых систем; каждая строка файла содержит имя устройства, имя точки монтирования, тип файловой системы и флаги монтирования.
В настоящее время в UNIX-подобных операционных системах представлено большое количество самых разнообразных языков программирования, каждый из которых обладает своими преимуществами. При разработке программы был выбран язык C и соответствующий ему компилятор из пакета gcc (GNUcompilerscollection) по следующим причинам:
· В силу того, что само ядро операционной системы написано на языке C, компилятор языка, входящий в состав пакета gcc, постоянно обновляется и исправляется, что практически исключает ошибки при компиляции с его стороны; в свою очередь, это приводит к генерации наиболее оптимизированного кода;
· Язык C предполагает использование простых конструкций, что выгодно отличает его от остальных языков, особенно интерпретируемых и объектно-ориентированных, с точки зрения скорости выполнения программ;
· Язык C предоставляет программисту наиболее полный доступ ко всем возможностям программного интерфейса POSIX, что позволяет наиболее эффективно организовывать взаимодействие программы с операционной системой.
Разработанная программа имеет возможность параллельной обработки запросов от нескольких клиентов. Это достигнуто за счет использования более чем одного потока управления, осуществляющих обработку запросов.
Потоки в системе Linux реализуются посредством программного интерфейса, предоставляемого входящей в состав Linux библиотеки потоков libpthread.
Создание потока разбивается на несколько этапов:
1. Описание функции, которая будет выполняться в рамках потока. Эта функция не должна содержать статических переменных.
2. Создание экземпляра описателя атрибутов потока – структуры типа pthread_attr_t, – и заполнение ее полей в соответствии с необходимыми свойствами создаваемого потока.
3. Создание переменной типа pthread_t, которая будет служить идентификатором создаваемого потока.
4. Создание потока с помощью функции pthread_create(), в которую передается указатель на идентификатор потока, указатель на описатель атрибутов потока, а также адрес поточной функции и ее аргумент.
После создания поток выполняется параллельно с остальными потоками процесса и завершает свою работу при выполнении в поточной функции оператора return или принудительном завершении извне.
Для обеспечения безопасности доступа выполняющихся потоков к разделяемым переменным, коими являются, например, переменные состояния систем журналирования и безопасности, используется механизм взаимоблокировки потоков с помощью объекта ядра – мьютекса.
Мьютекс представляет собой переменную типа pthread_mutex_t, к которой применимы две операции:
· pthread_mutex_lock – захват мьютекса; при применении этой операции к захваченному другим потоком мьютексу вызвавший поток блокируется до освобождения мьютекса.
· pthread_mutex_unlock – освобождение мьютекса.
Для контроля числа одновременно обслуживаемых запросов в серверном модуле применяется объект ядра – семафор.
Семафор представляет собой переменную типа sem_t, к которой применимы две основных операции:
· sem_wait – уменьшает на 1 текущее значение семафора; если текущее значение равно 0, поток блокируется;
· sem_post – увеличивает на 1 значение семафора.
Начальное значение семафора задается при его инициализации с помощью функции sem_init().
Сокет представляет собой объект, предоставляющий программный интерфейс к протоколу TCP/IPи являющийся конечной точкой подключения. Использование сокета ничем не отличается от использования операций ввода-вывода применительно к файловому дескриптору – к сокету применяются те же функции read() и write(), что и при файловом вводе-выводе. Существуют, однако, специфические функции send() и recv(), расширяющие функциональность стандартных read() и write(), но их использование не является обязательным.
Перед началом процесса передачи данных через сокет необходимо совершить ряд действий:
1. Создать переменную типа int, которая будет выступать в качестве дескриптора сокета.
2. Создать описатель адреса сокета – структуру типа sockaddr_in, – и заполнить ее поля в соответствии с адресом и портом, через которые планируется устанавливать соединение.
3. Создать объект «сокет» с помощью функции socket(). Значение, возвращенное функцией, присваивается дескриптору сокета.
4. Привязать сокет к адресу и порту с помощью функции bind().
5. Начать прослушивание адреса и порта на предмет входящих соединений с помощью функции listen().
6. Принимать соединения с помощью функции accept().
Следует заметить, что процедура инициализации клиентского сокета выполняется несколько иначе и не рассматривалась в силу того, что разработанная программа не выступает в качестве клиента.
Контроль сигналов используется в программе для прекращения работы сервера. При поступлении определенного сигнала обнуляется переменная-условие, в результате чего цикл приема сообщений прерывается.
Установка некоторой функции в качестве обработчика сигнала производится следующим образом:
1. Определение функции – обработчика сигнала.
2. Создание и заполнение описателя параметров обработчика – структуры типа sigaction. Одно из полей описателя содержит адрес функции-обработчика.
3. Назначение обработчика сигнала с помощью функции sigaction().
Для достижения наибольшей эффективности работы программы, возможности контроля исключительных ситуаций и легкости внесения модификаций, при разработке программы применялись элементы концепции структурного программирования, что привело к необходимости выделять ряд модулей, содержащих функции, сгруппированные по выполняемым ими задачам.
Все модули программы можно разделить на несколько групп:
· Система инициализации – обеспечивает настройку всех систем и запуск сервера.
· Сервер – обеспечивает настройку сетевых средств, принятие входящих подключений и передачу данных.
· Система управления подключаемыми библиотеками – предоставляет серверному модулю интерфейс загрузки динамических библиотек и выполнения содержащихся в них функций.
· Система журналирования – предоставляет всем модулям интерфейс для записи событий во внешний файл (журнал).
· Система безопасности – обеспечивает управление учетными записями и проверку авторизации пользователя.
· Динамические библиотеки – подключаются во время работы программы по запросам и реализуют получение системной информации.
· Дополнительные модули – содержат вспомогательные функции.
Системы и их взаимодействие представлены на рисунке 3.1: