Разработать сервер для отдачи статического содержимого с диска по протоколу HTTP:
- Предусмотреть поддержку запросов GET и HEAD, поддержку статусов 200, 403, 404.
- Предусмотреть возможность ответа сервера на неподдерживаемые запросы статусом 405.
- Обеспечить корректную передачу файлов размером до 128 Мбайт.
- Реализовать мультиплексирование - каждый процесс или поток должен отдавать данные по нескольким сетевым соединениям.
- Сервер по умолчанию должен возвращать HTML-страницу на выбранную тему с CSS-стилем.
- Реализовать запись информации о событиях в журнал (лог).
- Учесть минимальные требования к безопасности серверов статического содержимого.
Провести нагрузочное тестирование разработанного сервера:
- Максимальное количество обслуживаемых сетевых соединений
- Скорость отдачи данных по каждому сетевому соединению и совокупная
Варианты архитектуры разрабатываемого сервера: 3. thread pool + pselect()
При использовании в разработке платформы BSD/MacOS следует заменить системный вызов epoll() на kqueue()
Оформление курсовой работы:
- Расчётно-пояснительная записка на 12-32 листах А4
- Презентация к курсовой работе на 8-16 слайдах
Вопросы и ответы (на основе опыта защит в предыдущие годы)
Вопрос: Какую операционную систему использовать? Ответ: Систему, в которой есть системные вызовы fork(), select(), pselect(), poll(), epoll(). Это любой современный Линукс и различные системы семейства *BSD (FreeBSD как пример). На Windows вариант с prefork вы реализовать не сможете.
Вопрос: На каком языке программирования писать? Ответ: На языке, который позволяет обращаться к вышеуказанным системным вызовам (с помощью стандартной библиотеки). Это языки C, C++, Swift, Rust. Высокоуровневые фреймворки (вроде SwiftNIO) использовать нельзя. Языки, которые сами по себе высокоуровневый фреймворк (Python, Go) - также использовать нельзя.
Вопрос: Какие библиотеки можно использовать? Ответ: Можно пользоваться стандартной библиотекой соответствующего языка. Если вы нашли какую-либо библиотеку или фреймворк, которые хотите использовать, но у вас есть сомнения - задайте вопрос руководителю по электронной почте. В любом случае - исходный код такой библиотеки должен быть либо включен в дерево исходников вашего проекта (если лицензия позволяет), либо ее подключение должно быть описано в инструкции по сборке проекта.
Вопрос: Какие есть материалы по данной теме? Ответ: Если требуется быстро войти в курс дела, рекомендуется ознакомиться со вторым томом книги А. В. Столярова "Программирование: введение в профессию", выложена в электронном виде по ссылке http://stolyarov.info/books/programming_intro/2_91, вам нужны части 6 и 7. Еще рекомендуется посмотреть эту статью https://habr.com/ru/companies/infopulse/articles/415259/ и этот мини-проект https://github.com/jamesmacinnes/http-buddy/ Если есть желание углубиться в тему, рекомендую Michael Kerrisk "The Linux Programming Interface" https://man7.org/tlpi/index.html (pdf есть в Интернете). Также в любом Линуксе по указанным системным вызовам есть отличные man-страницы, с примерами.
CmpleWebServer - это легковесный веб-сервер, написанный на C, реализующий архитектуру thread pool + pselect() для эффективной обработки HTTP-запросов. Сервер предназначен для отдачи статического контента и демонстрирует фундаментальные концепции сетевого программирования.
CmpleWebServer/
├── src/ # Основной исходный код
│ ├── main.c # Точка входа и обработка аргументов командной строки
│ ├── server/ # Основная логика сервера
│ │ ├── server.c # Управление сервером и сетевыми соединениями
│ │ ├── worker.c # Обработка запросов в потоках
│ │ └── request.c # Парсинг и обработка HTTP-запросов
│ ├── reader/ # Асинхронное чтение файлов
│ │ ├── reader.c # Пул асинхронных читателей файлов
│ │ └── stat.c # Получение информации о файлах
│ ├── cache/ # Кэширование в памяти
│ │ └── cache.c # Реализация LRU-кэша
│ └── utils/ # Вспомогательные утилиты
│ ├── content.c # Определение типов контента
│ ├── date.c # Работа с датами в HTTP-формате
│ ├── hash.c # Хеширование
│ ├── log.c # Система логирования
│ ├── string.c # Работа со строками
│ └── strutils.c # Дополнительные строковые утилиты
├── inc/ # Заголовочные файлы
│ ├── server/ # Заголовки для сервера
│ ├── reader/ # Заголовки для чтения файлов
│ ├── cache/ # Заголовки для кэширования
│ └── utils/ # Заголовки для утилит
├── data/ # Статические файлы для отдачи
│ ├── index.html # Главная страница
│ ├── styles.css # Стили для главной страницы
│ ├── favicon.ico # Фавикон
│ ├── favicon.png # Альтернативный фавикон
│ └── readme.png # Изображение для README
├── docs/ # Документация
│ ├── report.pdf # Отчет по курсовой работе
│ ├── pres.pdf # Презентация
│ └── pregen.pdf # Дополнительные материалы
├── scripts/ # Скрипты для тестирования
│ ├── ab_runner.py # Скрипт для нагрузочного тестирования
│ ├── plmc.py # Скрипт для тестирования кэша
│ └── plts.py # Скрипт для тестирования производительности
├── testdata/ # Данные для тестирования
├── dist/ # Скомпилированные бинарники
├── obj/ # Объектные файлы
├── Makefile # Скрипт сборки
└── README.md # Документация проекта
Основной сервер создает слушающее сокет-соединение и распределяет входящие соединения между рабочими потоками. Он использует мьютексы для синхронизации доступа к общим ресурсам.
Сервер использует пул потоков для обработки HTTP-запросов. Каждый рабочий поток:
- Обрабатывает несколько соединений одновременно
- Использует pselect() для мультиплексирования I/O операций
- Управляет состоянием запросов через конечный автомат
- Взаимодействует с кэшем и пулом читателей файлов
Для предотвращения блокировки рабочих потоков при чтении файлов реализован отдельный пул асинхронных читателей файлов. Это позволяет:
- Выполнять операции чтения вне рабочих потоков
- Обеспечивать неблокирующую обработку запросов
- Эффективно использовать системные ресурсы
Сервер реализует LRU (Least Recently Used) кэш в памяти для ускорения отдачи часто запрашиваемых файлов:
- Кэш имеет ограничения по памяти, количеству записей и размеру отдельных файлов
- При достижении лимитов автоматически удаляются наименее используемые записи
- Поддерживает многопоточный доступ с использованием RW-локов
- Использует хеширование для быстрого поиска
Сервер реализует полный цикл обработки HTTP-запросов:
- Парсинг HTTP-запросов (метод, путь, заголовки)
- Поддержка методов GET и HEAD
- Формирование корректных HTTP-ответов с заголовками
- Обработка ошибок (404, 403, 405)
- Управление состоянием соединения
Каждый рабочий поток использует pselect() для одновременного наблюдения за несколькими сокетами. Это позволяет эффективно обрабатывать множество соединений в одном потоке без блокировок.
Обработка каждого запроса реализована как конечный автомат со следующими состояниями:
- CONNECT: Новое соединение
- READ: Чтение данных запроса
- WAITING_FOR_BODY: Ожидание чтения тела файла
- WRITE: Запись ответа клиенту
- DONE: Завершение обработки
- ERROR: Обработка ошибки
Реализована гибкая система логирования с поддержкой различных уровней (DEBUG, INFO, WARN, ERROR) и цветового выделения в терминале.
Сервер учитывает базовые требования безопасности:
- Проверка типа файла перед отдачей
- Ограничение размера отдаваемых файлов
- Корректная обработка ошибок
- Защита от некоторых типов атак через валидацию путей
Оптимизации для высокой производительности:
- Минимизация системных вызовов
- Эффективное управление памятью
- Асинхронная обработка I/O операций
- Кэширование часто запрашиваемых ресурсов
- gcc
- make
- libcheck (для тестирования) https://libcheck.github.io/check/
make all && ./main.appmake test && ./test.app