Как сделать http сервер
Первое знакомство с протоколом HTTP через написание простейшего Web сервера на Java
Думаю что не будет преувеличением утверждать, что знание и понимание сути протокола HTTP необходимо любому, кто решил сколь-нибудь серьезно заняться любым из направлений современной Web разработки. Мой личный опыт говорит о том, что понимание это приходит не сразу. Стыдно сказать, что были времена, когда слова GET и POST были для меня сродни магическим заклинаниям, а о существовании PUT, PATCH и DELETE я даже не подозревал.
Несколько месяцев назад помимо собственно разработки я занялся также преподаванием, и возник вопрос о том, как проще и понятнее рассказать о сути протокола HTTP будущим Java разработчикам. После нескольких дней возни и ряда неудачных попыток сделать презентацию возникла идея, а почему бы не написать простейший HTTP сервер на Java, потому как ни что так хорошо не объясняет суть протокола, как его простейшая, но работающая реализация.
Как оказалось сделать это совсем не сложно. Ниже привожу код, которого будет достаточно для корректного взаимодействия с любым браузером! Все что нам понадобится это ServerSocket и немного стандартного ввода-вывода.
Пробуем запустить этот код. Стоит отметить, что порт, для которого создается ServerSocket должен быть свободным. Если указанный порт занят, то нужно или его освободить, или использовать другой свободный порт.
Каждый раз, когда мы что-то вводим в адресную строку браузера и нажимаем Enter не происходит ничего иного, как отправка текста, начинающегося словом GET и заканчивающегося переводом строки. После слова GET через пробел следует путь к запрашиваемому документу на сервере. Попробуйте ввести в браузере http://localhost:8080/something и посмотреть, как изменится текст запроса в логе.
После того, как текст запроса полностью прочитан сервером, мы отправляем ему простейший ответ, структура которого довольно проста и аналогична структуре запроса. В первой строке версия протокола HTTP и код 200 OK, который сообщит браузеру о том, что запрос был успешно обработан (всем куда лучше знаком код 404, не правда ли 😉 ). Далее следует всего один заголовок Content-Type в котором передается информация о формате передаваемого документа (text/html) и его кодировке (charset=utf-8). После заголовка следует перевод строки (обязательное требование протокола HTTP) и собственно текст, который будет отображен в браузере.
На этом все! Разумеется это далеко не все, что нужно знать о протоколе HTTP и принципах разработки Web серверов, но мне бы не хотелось усложнять данный пример, т.к. главная его задача — продемонстрировать, простейшую коммуникацию по протоколу HTTP. В одном из следующих своих материалов постараюсь развить тему изучения протокола HTTP через его реализацию.
UPD. Гораздо более продвинутый пример подобного сервера можно найти в книге How Tomcat Works: A Guide to Developing Your Own Java Servlet Container by Paul Deck, Budi Kurniawan, глава 1 — Simple Web Server.
Домашний веб-сервер, или сам себе хостинг-провайдер
Для того, чтобы сделать свой веб-сервер дома, нам понадобится компьютер и постоянный доступ в интернет с внешним IP-адресом, как это проверить описано дальше.
Делать сервер буду из старого нетбука Samsung N102SP со сломанной клавиатурой, для небольших нагрузок его вполне достаточно, к тому же он маленький и совсем не шумит. Интернет дома у меня раздаётся wifi роутером tp-link TL-WR840N, через него и буду подключать свой сервер.
Ставить буду Centos 7, качаем отсюда минимальный образ (Minimal ISO), образ записываю на флешку с помощью программы Rufus. Теперь надо загрузить нетбук с флешки, и тут возникает первая проблема, так как клавиатура не работает, не могу войти в биос, внешнюю usb клавиатуру он не видит, сброс биоса решает проблему (в нетбуке Samsung N102SP биос сбрасывается замыканием контактов rtc reset под крышкой memory, замыкать надо на 30 секунд), выбираем в биосе приотритетную загрузку с флешки и начинаем установку, даже при минимальной версии Centos 7 устанавливается в графическом режиме. Никаких сложностей с установкой возникнуть не должно, удаляем все старые разделы на диске и отдаём все под Centos, устанавливаем пароль root и прописываем настройки сети, в моем случае подключаемся к домашней сети wifi (это можно сделать и потом с помощью команды nmtui), несколько минут и Centos 7 установлен.
Заходим под root. Останавливем firewall командой «systemctl stop firewalld», отключаем firewall из автозагрузки командой «systemctl disable firewalld». Пока он нам не нужен, настроим firewall позже. Еще надо обязательно отключить спящий режим при закрытии крышки нетбука, для этого надо в файле /etc/systemd/logind.conf заменить строку «#HandleLidSwitch=suspend» на строку «HandleLidSwitch=ignore», затем перезапустить командой «systemctl restart systemd-logind».
Теперь можно мой нетбук поставить в удаленный угол и забыть про его физическое существование, все дальнейшие действия со своим домашним веб-сервером можно произвоить через ssh.
Теперь нужно настроить wifi роутер, в случае с tplink открываем tplinkwifi.net логин и пароль по умолчанию admin, в разделе «Состояние» смотрим состояние WAN, IP адрес должен быть статическим и не должен начинаться с 192.168.х.х, 172.х.х.х, 10.х.х.х, в противном случае свяжитесь с провайдером и попросите предоставить внешний IP, скорее всего это можно сделать и через личный кабинет, мой провайдер предоставил мне IP за 90 рублей в месяц. Все новые настройки нужно прописать в разделе «Сеть/WAN». Теперь нужно зарезервировать внутренний IP адрес на роутере для нашего сервера, заходим в раздел «DHCP/Список клиентов DHCP» и находим там наш сервер (чтобы узнать IP на сервере наберите команду ifconfig), после копируем MAC-адрес и переходим в раздел «DHCP/Резервирование адресов» и добавляем там MAC-адрес нашего сервера и его IP. Всё, теперь роутер всегда будет выделять для нашего сервера этот IP. Теперь надо пробросить порты, чтобы при обращении из интернета роутер отправлял запросы на домашний веб-сервер, заходим в раздел «Переадресация/Виртуальный сервер» и добавляем 80 порт. Также добавляем 22 порт, чтобы можно было подключаться к серверу через ssh. У меня при добавлении 80 порта возникала ошибка «Порт удалённого управления веб-интерфейсом конфликтует с портом виртуального сервера». Чтобы этого избежать предварительно изменим порт удалённого управления на 8080, для этого откроем вкладку «Защита/Удалённое управление». Теперь управление роутером доступно по адресу tplinkwifi.net:8080/
Для удалённого управления веб-сервером качает утили Putty с www.chiark.greenend.org.uk/
Теперь для полнофункционнальной работы веб-сервера установим необходимые компоненты, первым делом подключим репозиторий Epel, там есть практически всё необходимое для автоматической установки, вводим команду «yum install epel-release». Затем для отслеживания состояния сервера устанавливаем htop командой «yum install htop», для удобной работы с файлами усталавливаем midnight commander, командой «yum install mc», теперь ставим Apache, для этого вводим «yum install httpd», запускаем и ставим в автозагрузку командами «systemctl start httpd» и «systemctl enable httpd», теперь установим MariaDB командой «yum install mariadb-server», аналогично запускаем и ставим в автозагрузку «systemctl start mariadb» и «systemctl enable mariadb», производим первичные настройки при помощи команды «mysql_secure_installation», устанавливаем root пароль, удаляем анонимного пользователя и тестовую базу, затем нужно устанавить PHP с необходимыми модулями «yum install php php-mysql php-common php-mbstring php-mcrypt php-devel php-xml php-gd», перезагружаем httpd командой «systemctl restart httpd». Теперь при вводе в браузере IP адреса видим приветственную страницу Apache. Корневой каталог находится в «/var/www/html/». Вот теперь наш домашний веб-сервер доступен с любой точки планеты.
Создание многопоточного сервера на C#
Предисловие
Данная статья предназначена для таких же новичков как и я. Вся информация в этой статье основывается на моем опыте создания одного единственного веб-сервера, который был создан в рамкам учебного проекта на 3 курсе по специальности 09.02.07 СПО.
Веб-сервер
Прежде чем писать свой веб сервер, нам нужно понять что это и как он работает.
Под веб-сервером подразумевают две вещи:
В данной статье мы будем рассматривать веб-сервер, как программное обеспечение.
Чтобы было понятнее, разобьем работу архитектуры по пунктам:
Формирование запроса клиентом
Отправка запроса на сервер
Получение запроса на сервере
Обработка запроса и формирование ответа
Отправка ответа клиенту
Реализация веб сервера на C#
Для начала мы должны создать 2 класса(они должны располагаться в двух новых файлах):
Затем в классе мы должны создать переменные которыми будем оперировать:
Теперь создадим конструктор для нашего класса. Так как Socket работает по ip:port, то и наш конструктор будет принимать первым аргументом ip, а вторым port:
AddressFamily – перечисление, которое обозначает то, с какой версией ip адресов мы будем работать. InterNetwork говорит о том что мы используем IPv4.
После конструктора нам стоит создать две функции, первая будет инициализировать работу нашего сервера, а вторая останавливать его соответственно:
Условие внутри функции проверяет, выключен ли сервер. Если он выключен, то мы можем запустить наш сервер. Это нужно для того, чтобы не было конфликта у сокета. Если мы попытаемся запустить второй сокет с тем же ip и port то вылезет ошибка.
После мы заполняем наше условие, если сервер выключен то:
Функция Bind класса Socket означает, что слушатель будет работать по определенному ip:port, который мы передаем в эту функцию.
Но такой способ не эффективен, так как он будет просто создавать новые потоки для обработки входящего соединения, тем самым тормозя работу сервера, ведь как никак потоки у нашего процессора не безграничны. Поэтому мы берем и вставляем этот кусок кода в наше условие(после Active = true ):
Функция будет циклически прослушивать входящие соединения. Listener.Accept() будет временно останавливать цикл, до тех пор, пока не придет запрос на подключение.
Теперь перейдем к нашей функции остановки сервера:
Данная структура будет хранить значения наших HTTP заголовков:
RealPath – хранит полный путь до файла на нашем сервере(пример: C:\Users\Public\Desktop\Server\www\index.html)
Теперь давайте создадим саму функцию, которая будет парсить заголовки:
Она будет возвращать саму структуру, тогда объявление структуры будет выглядеть так:
Теперь опишем тело функции:
Объяснять принцип работы регулярных выражений я не буду, поэтому в конце статьи есть ссылка на документацию.
Теперь давайте напишем функцию, которая будет возвращать нам расширения нашего файла, назовем ее FileExtention :
Опять же, делаем это с помощью регулярных выражений.
Эта структура была сделана для удобства, так как когда мы будет парсить большое кол-во заголовков, то лучше если они будут храниться в одном месте.
Создадим в классе Client переменные:
У конструктора нашего класс будет всего 1 аргумент, который будет принимать Socket :
После в конструкторе, мы должны присвоить нашей переменной client наш аргумент и начать принимать данные от клиента:
Код представленный выше описывает то, как сервер принимает запросы от клиента:
Теперь настало время проверок и парсинга наших заголовков.
Если у нас все же что-то пришло, то время воспользоваться структурой и распарсить принятое сообщение и выводим сообщение о подключении в консоль:
Ну и наконец последняя проверка в этой функции, если файл по указанному пути Headers.RealPath существует, то мы начинаем работать с этим файлом, иначе выводи ошибку:
Теперь создадим функцию, которая будет возвращать тип контента, так как в данной статье представлена простая версия сервера, то мы ограничимся типами: text и image. Тип контента мы выводим для того, чтобы отправленный нами файл мог опознаться, записываем мы это значение в специальном заголовке Content-Type (пример: Content-Type: text/html ):
Теперь опишем нашу последнюю функцию GetSheet и можно будет тестировать наш сервер:
Теперь опишем тело оператора try :
Первый параметр указывает на минимальное кол-во работающих потоков, а второй на минимальное кол-во асинхронно работающих потоков. Минимальное значение стоит всегда указывать 2, так как если указать 1, то основной поток будет блокироваться для обработки запроса.
Теперь зададим максимальные значения для нашего пула:
После чего мы просто инициализируем наш класс Server в функции и запускаем его:
После этого прописываем в адресной строке: http://127.0.0.1/index.html и проверяем результат. Нам должно вывести надпись Hello Server!, а так же должно вывести в консоли данные о нынешнем подключении.
Теперь Вы имеете представление о том, как с помощью сетевых сокетов на языке C# реализовать простой, многопоточный сервер. Для большего понятия как работают разные классы рекомендую почитать документацию:
Благодарю за то что уделили моей статье внимание, надеюсь что если я где-то оказался не прав вы укажете мне на это в комментариях и поможете стать лучше.
Ссылка на сервер на GitHub, в данной версии сервера реализована поддержка php.
Свой http-сервер менее чем в 40 строк кода на libevent и C++11

Для себя как-то по работе я рассматривал libevent и libev. У каждой есть свои преимущества. Если же есть желание или потребность в скорой разработке небольшого http-сервера, то для меня большой интерес представляет libevent, а с учетом некоторых новшеств C++11 код становится намного компактнее и позволяет создать базовый http-сервер менее, чем в 40 строк.
Материал поста возможно будет полезен тем, кто еще не знаком с libevent и есть потребность в скором создании своего http-сервера, а так же материал может заинтересует людей, у которых такой потребности пока нет и даже если они уже имели опыт создания подобного, интересно узнать их мнение и опыт. А так как пост не содержит ничего принципиально нового, то может быть использован как материал для начала работы в данном направлении, а следовательно попробую поставить пометку «обучающий материал».
Чем хороша libevent в отличии от, например, libev и boost.asio, так это тем, что она имеет свой встроенный http-сервер, и некоторую абстракцию для работы с буферами. А так же имеет немалый набор вспомогательных функций. Можно HTTP протокол и самому разобрать, написав простенький конечный автомат или еще каким-нибудь методом. При работе с libevent это все уже есть. Эта такая приятная плюшка, а можно и на более низкий уровень спуститься и писать свой же парсер для HTTP, при этом работу с сокетами сделать на libevent. Уровень детализации у библиотеки мне понравился тем, что если есть желание сделать что-то быстро, то можно найти в ней более высокоуровневый интерфейс, который как правило менее гибок. При появлении больших потребностей можно постепенно спускаться уровень за уровнем все ниже и ниже. Библиотека позволяет делать многие вещи: асинхронный ввод-вывод, работу с сетью, работа с таймерами, rpc, т. д; можно с ее помощью создавать как серверное, так и клиентское ПО.
Зачем?
Создание собственного небольшого http-сервера может быть обусловлено для каждого его собственными потребностями, желанием или не желанием использовать полнофункциональные готовые сервера по той или иной причине. Предположим у Вас есть некоторое серверное ПО, которое работает по какому-то своему протоколу и решает некоторые задачи и у Вас появилась потребность выдать некоторое API для данного ПО через HTTP протокол. Возможно всего несколько небольших функций по настройке сервера и получению его текущего состояния по протоколу HTTP. Например, организовав обработку запросов GET с параметрами и отдавать небольшой xml с ответом или еще в каком-то формате. В таком случае можно с малыми трудозатратами создать свой http-сервер, который и будет интерфейсом для основного Вашего серверного ПО. Кроме этого если есть необходимость создать свой небольшой специфичный сервис по раздаче какого-то набора файлов или даже создать свое собственное веб-приложение, то можно так же воспользоваться таким самописным небольшим сервером. В общем можно воспользоваться как для построения самодостаточного серверного ПО, так и для создания вспомогательных сервисов в рамках более крупных систем.
Простой http-сервер менее чем в 40 строк
Получилось менее 40 строк, которые способны обрабатывать http-запросы, отдавая в ответ строку «Hello World», а если заменить функцию evbuffer_add_printf на evbuffer_add_file, то можно отправлять файлы. Можно такой сервер назвать базовой комплектацией. Любой авто дилер или риэлтор в большинстве своем мечтают, чтобы их авто и квартиры никогда и ни при каких условиях не уходили в базовой комплектации, а только с дополнительными опциями. А вот нужны ли такие опции потребителю и в каком объеме…
Что может дать такая базовая комплектация по быстродействию можно проверить с помощью утилиты ab для *nix систем с небольшой вариацией параметров.
Server Software:
Server Hostname: 127.0.0.1
Server Port: 5555
Document Path: /
Document Length: 64 bytes
Concurrency Level: 1000
Time taken for tests: 2.289 seconds
Complete requests: 50000
Failed requests: 0
Write errors: 0
Keep-Alive requests: 50000
Total transferred: 8500000 bytes
HTML transferred: 3200000 bytes
Requests per second: 21843.76 [#/sec] (mean)
Time per request: 45.780 [ms] (mean)
Time per request: 0.046 [ms] (mean, across all concurrent requests)
Transfer rate: 3626.41 [Kbytes/sec] received
Connection Times (ms)
min mean[±sd] median max
Connect: 0 3 48.6 0 1001
Processing: 17 42 9.0 43 93
Waiting: 17 42 9.0 43 93
Total: 19 45 49.7 43 1053
Server Software:
Server Hostname: 127.0.0.1
Server Port: 5555
Document Path: /
Document Length: 64 bytes
Concurrency Level: 1000
Time taken for tests: 5.004 seconds
Complete requests: 50000
Failed requests: 0
Write errors: 0
Total transferred: 6300000 bytes
HTML transferred: 3200000 bytes
Requests per second: 9992.34 [#/sec] (mean)
Time per request: 100.077 [ms] (mean)
Time per request: 0.100 [ms] (mean, across all concurrent requests)
Transfer rate: 1229.53 [Kbytes/sec] received
Connection Times (ms)
min mean[±sd] median max
Connect: 0 61 214.1 20 3028
Processing: 7 34 17.6 31 277
Waiting: 6 28 16.9 25 267
Total: 17 95 219.5 50 3055
Тест проводился на уже не совсем новом ноутбуке (2 ядра, 4Гб оперативной памяти) под управлением 32-х битной операционной системы Ubuntu 12.10.
Многопоточный http-сервер
Нужна ли многопоточность? Вопрос риторический… Можно все IO и в одном потоке организовать, а запросы складывать в очередь и разгребать ее в несколько потоков. В таком случае вышеприведенный сервер можно просто дополнить очередью и пулом потоков для обработки и больше ничего городить не стоит. Если же есть желание или потребность построить многопоточный сервер, то он будет немного длиннее предыдущего, однако ненамного. C++11 с его умными указателями позволяют хорошо реализовывать RAII, как это было приведено с std::unique_ptr в примере выше, а также наличие лямбда-функций немного сокращает код.
Пример многопоточного сервера по своей идеологии аналогичен однопоточному, а некоторые особенности, связанные с многопоточностью его увеличивают примерно в 2 раза по объему кода. Восемьдесят с небольшим строк кода для многопоточного http-сервера на C++ — это не так и много.
В коде можно заметить, что каждый поток создается после некоторого внесенного ожидания. Это небольшой хак, который уже будет исправлен в конечной версии сервера. Пока можно сказать только, что если этого не сделать, то потоки надо будет как-то синхронизировать, чтобы они отработали «странный шаг» по созданию и привязке сокета. Для упрощения пока пусть останется такой хак. Так же в приведенном коде лямбда-функция может показаться спорным решением. Лямбды могут быть хорошим решением при использовании, например, в качестве некоторого предиката при работе со стандартными алгоритмами. В то же время можно задуматься об их использовании и при написании более больших фрагментов кода. В примере выше можно было все вынести в обычную функцию, передать все нужные параметры и получить код в стиле C++03. В то же время использование лямбды дало сокращение в объеме кода. На мой взгляд, когда код невелик, то лямбды могут вполне хорошо в него вписывать даже с не самым коротким ее содержанием и не влиять пагубно на качество кода, конечно не стоит вдаваться в крайности и вспоминать студенческие будни с написанием лабораторной работы в 700 строк в единственной функции main.
Тестирование многопоточного сервера проведено с теми же параметрами, что и предыдущего примера.
Server Software:
Server Hostname: 127.0.0.1
Server Port: 5555
Document Path: /
Document Length: 64 bytes
Concurrency Level: 1000
Time taken for tests: 1.576 seconds
Complete requests: 50000
Failed requests: 0
Write errors: 0
Keep-Alive requests: 50000
Total transferred: 8500000 bytes
HTML transferred: 3200000 bytes
Requests per second: 31717.96 [#/sec] (mean)
Time per request: 31.528 [ms] (mean)
Time per request: 0.032 [ms] (mean, across all concurrent requests)
Transfer rate: 5265.68 [Kbytes/sec] received
Server Software:
Server Hostname: 127.0.0.1
Server Port: 5555
Document Path: /
Document Length: 64 bytes
Concurrency Level: 1000
Time taken for tests: 3.685 seconds
Complete requests: 50000
Failed requests: 0
Write errors: 0
Total transferred: 6300000 bytes
HTML transferred: 3200000 bytes
Requests per second: 13568.41 [#/sec] (mean)
Time per request: 73.701 [ms] (mean)
Time per request: 0.074 [ms] (mean, across all concurrent requests)
Transfer rate: 1669.55 [Kbytes/sec] received
Connection Times (ms)
min mean[±sd] median max
Connect: 0 36 117.2 23 1033
Processing: 3 37 10.0 37 247
Waiting: 3 30 8.7 30 242
Total: 9 73 118.8 61 1089
Конечный вариант сервера
Базовая комплектация приведена, комплектация с небольшим набором опций так же есть. Теперь очередь подошла и для создания чего-то более полезного и функционального, а так же с небольшим тюнингом.
Весьма минимальный объем кода для http-сервера на C++. За все есть плата. И в данном случае такая простота клиентского кода по созданию сервера, оплачена более длинной реализацией, скрытой в предлагаемой обертке над libevent. На самом же деле ненамного увеличилась реализация. Чуть ниже ее фрагменты будут описаны.
Данный интерфейс позволяет получать из входящего запроса его тип, некоторые атрибуты (заголовки), размер тела запроса и само тело запроса при его наличии, а так же формировать ответ с возможностью задать атрибуты (заголовки), код завершения обработки запроса и тело ответа (в данной реализации имеются методы для передачи строки, некоторого буфера или файла в ответ). Каждый метод в его реализации может генерировать исключение типа HttpRequestException.
Если еще раз взглянуть на код сервера, то в коде обработки запросов можно заметить такие строки:
Это формирование заголовка ответа, а данном примере задаются такие поля заголовка, как «Content-Type» и «Server». Не смотря на то, что libevent имеет достаточно широкий функционал, выходящий далеко за потребности HTTP, списка констант полей заголовков в ней нет; есть только неполный список кодов возврата (наиболее часто используемых). Чтобы не возиться со строками, определяющими поля заголовков (например, во избежании опечаток в пользовательском коде), все константы определены уже в предлагаемой обертке над libevent.
Почти аналогичным образом определены и константы для задания типа контента; имеют небольшую модификацию. Было желание реализовать поиск типа контента по расширению файла для удобства при отправке файлов в ответ на запрос.
При желании что-то получить из входящего запроса, например, с какого хоста и с какой страницы был осуществлен переход на запрашиваемый ресурс и, например, есть ли у пользователя «печеньки», можно это все получить из заголовка входящего запроса таким образом:
Аналогичным образом в ответе можно, например, установить пользователю некоторые Cookie, по которым в дальнейшем работать с его сессией и отслеживать при желании его блуждания по Вашему ресурсу (пример работы с заголовками ответа приведен в кода сервера).
Если же есть желание организовать некоторое свое API через HTTP, то это так же легко сделать. Предположим надо создать методы: открытие сессии, получение статистической информации о сервере и закрытие сессии. Пусть для этого строки запроса к Вашему серверу будут выглядеть примерно так:
Ответом на эти строки запросов сервер пользователя может сгенерировать какой-то ответ, например, в формате xml. Это дело разработчика сервера. А вот как работать с такими запросами, получать из них параметры приведено ниже:
Один из путей для примеров выше будет таким /service/login/OpenSession, а параметры это карта из переданных пар ключ / значение. Тип карты параметров:
После разбора всего того, что можно реализовать с помощью предлагаемой конечной версии обертки над libevent можно заглянуть и под капот этой самой обертки.
Функцию обработки запросов можно посмотреть в полной версии, скачав исходные файлы примеров, она стала немного больше, чем в ранее приведенных примерах, и перестала претендовать на лямбду без потери читаемости кода. Так же не стал приводить реализацию интерфейса IHttpRequest, так как она мало интересна своей рутинной работой с буфером libevent. А в остальном если посмотреть на код итоговой версии, он не сильно-то изменился. Небольшая модификация и добавилось немного «тюнинга».
Сервер пользователя не обязан обрабатывать все типы http-запросов. Можно задать список типов запросов, которые сервер должен обрабатывать и для этого libevent имеет функцию evhttp_set_allowed_methods (а по умолчанию обертка задает только тип запросов GET). При задании списка обрабатываемых запросов на все остальные libevent сама будет сообщать о невозможности выполнения такого запроса, тем самым избавив пользователя от дополнительных проверок.
Пытливость ума она бывает разной: нацеленной на созидание и на разрушение. От разрушительной пытливости ума с желанием «завалить» сервер послав ему какой-то непомерно для него большой заголовок http-пакета или сформировав большое тело запроса можно так же проактивно защититься функциями evhttp_set_max_headers_size и evhttp_set_max_body_size. Конечно же отправка больших запросов может быть вызвана не только недобрыми помыслами, а так же и иными причинами. Приведенные методы позволят немного сократить нежелательные аварийные завершения Вашего сервера. Возможно еще что-то предусмотреть, а в остальном уже можно реагировать реактивно, что как правило и происходит…
В конце приведу финальную версию, которая отрабатывает запросы GET (отдает файлы из указанной директории) и выводит на экран с какого хоста был сделан запрос и с какой страницы был осуществлен переход на ресурс, обрабатываемый сервером.
Заключение
Server Software: test
Server Hostname: test
Server Port: 8888
Document Path: /libevent_test_http_srv.zip
Document Length: 23756 bytes
Concurrency Level: 1000
Time taken for tests: 10.012 seconds
Complete requests: 2293
Failed requests: 0
Write errors: 0
Keep-Alive requests: 2293
Total transferred: 60628847 bytes
HTML transferred: 60328370 bytes
Requests per second: 229.02 [#/sec] (mean)
Time per request: 4366.365 [ms] (mean)
Time per request: 4.366 [ms] (mean, across all concurrent requests)
Transfer rate: 5913.65 [Kbytes/sec] received
Две с небольшим тысячи обработанных запросов на получение архива с исходными файлами примеров поста за десять секунд на уже весьма скромной конфигурации железа…