Маленький веб
Компактная и портабельная программа, четко выполняющая свое предназначение — редкая для современного мира красота и услада для глаз опытного разработчика.
Именно такие проекты, реализующие различные серверы и клиенты для веба вы найдете в этой статье.
Ода миниатюризации
Есть много причин, по которым миниатюрные девушк.. ээ реализации программ заслуживают внимания:
- обучение — врядли получится разобраться как устроен вебсервер, перелопачивая исходники монстров вроде Apache или Nginx, спасет только миниатюрная реализация;
- основа для собственных проектов — большой объем чужого исходного кода под капотом вашего проекта будет висеть гирей и отвлекать ресурсы на поддержку, в отличие от чего-то маленького и простого;
- борьба с энтропией — популярные библиотеки постоянно растут и раздуваются, при этом объем используемого функционала не особо меняется. Таким образом, большая часть кода в современном проекте с кучей внешних библиотек не используется никогда.
Разумеется есть определенные риски использования таких «наколенных» библиотек, связанные с неполной реализацией, безопасностью, работой под нагрузкой и так далее.
Но говоря откровенно, всего этого ныне хватает с головой и в больших популярных реализациях.
Еще с опытом приходит понимание, что любая программа — не более чем инструмент а реальную опасность, как и сто лет назад, представляют живые люди, не машины.
Тестовое окружение
Не стал опять заморачиваться с BSD, чтобы в третий раз не описывать специальную прослойку epoll-shim, позволяющую быстро и более-менее безболезненно портировать серверный софт с линукса.
На этот раз в качестве тестового окружения выступает обычная Ubuntu 25.10, хотя и с немного нестандартным ядром.
Компилятором выступит штатный GCC:
gcc version 15.2.0 (Ubuntu 15.2.0-4ubuntu4)
Sandbird
https://github.com/rxi/sandbird/tree/master
Начнем погружение с весьма практичного проекта:
A tiny (~800sloc) embeddable HTTP server written in C89, compatible with Linux, OSX and Windows.
800 строк на чистом С, причем наиболее портабельного стандарта С89, c поддержкой Windows, Linux и MacOS — отличный набор для реального применения, например в качестве встроенного вебсервера.
Например в каком-нибудь устройстве.
Один из примеров, демонстрирующих работу этой библиотеки — на заглавном скриншоте к статье, причем показана обработка формы.
Вот так выглядит сборка примера:
cd example gcc hello.c ../src/*.c -I../src -std=c89 -pedantic -Wall -Wextra -o hello
Так выглядит код тестового приложения с использованием этой библиотеки:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "sandbird.h"
static int event_handler(sb_Event *e) {
if (e->type == SB_EV_REQUEST) {
printf("%s - %s %s\n", e->address, e->method, e->path);
sb_send_status(e->stream, 200, "OK");
sb_send_header(e->stream, "Content-Type", "text/plain");
sb_writef(e->stream, "Hello world");
}
return SB_RES_OK;
}
int main(void) {
sb_Options opt;
sb_Server *server;
memset(&opt, 0, sizeof(opt));
opt.port = "8000";
opt.handler = event_handler;
server = sb_new_server(&opt);
if (!server) {
fprintf(stderr, "failed to initialize server\n");
exit(EXIT_FAILURE);
}
printf("Server running at http://localhost:%s\n", opt.port);
for (;;) {
sb_poll_server(server, 1000);
}
sb_close_server(server);
return EXIT_SUCCESS;
}сервер не использует многопоточность, все клиентские обработчики работают в одном потоке.
..
static void set_socket_non_blocking(sb_Socket sockfd) {
#ifdef _WIN32
u_long mode = 1;
ioctlsocket(sockfd, FIONBIO, &mode);
#else
int flags = fcntl(sockfd, F_GETFL);
fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
#endif
}
..webs
https://github.com/nicholascok/webs
Следующий интересный и даже в чем-то уникальный проект, с лаконичным описанием:
реализует с помощью ~700 строк на С89.. серверные вебсокеты!
Вебсокеты это чаты, это «live-streaming», например отображение логов в реальном времени и тому подобные динамические штуки.
Так выглядит сборка тестового приложения:
gcc -c *.c examples/test.c -Wall -Wextra -Wpedantic -Wno-overlength-strings -std=c89 gcc -o webs *.o -lpthread
Как нетрудно догадаться по -lpthread, тут уже используется многопоточность на базе POSIX threads:
..
static void* __webs_main(void* _srv) {
webs_server* srv = (webs_server*) _srv;
webs_client* user_ptr;
webs_client user;
for (;;) {
user.fd = __webs_accept_connection(srv->soc, &user);
user.srv = srv;
if (user.fd >= 0) {
user_ptr = __webs_add_client(srv, user);
pthread_create(&user_ptr->thread, 0, __webs_client_main,
user_ptr);
}
}
return NULL;
}
..К сожалению этот интересный проект по большей части прототип, иллюстрирующий как можно на коленке без внешних библиотек реализовать серверную сторону вебсокетов на чистом С.
В случае реального использования, столь вольное использование malloc для обработки входящих пакетов быстро превратится в проблему:
..
/* deal with normal frames (non-fragmented) */
if (WEBSFR_GET_OPCODE(frm.info) != 0x0) {
/* read data */
if (data) free(data);
data = malloc(frm.length + 1);
.. А вот так выглядит сокращенная версия тестового сервера для вебсокетов, c минимумом обработчиков:
#include "../webs.h"
int myFuncZ(webs_client* self) {
printf("server %ld: (id %ld) connected!\n",
self->srv->id, self->id);
webs_send(self, "greetings, salutations!");
return 0;
}
int myFunc2(webs_client* self) {
printf("server %ld: (id %ld) disconnected!\n",
self->srv->id, self->id);
return 0;
}
int main(void) {
webs_server* server1 = webs_start(7754);
if (!server1) {
printf("failed to initialise a server.\n");
return 1;
}
server1->events.on_open = myFuncZ;
server1->events.on_close = myFunc2;
webs_hold(server1);
webs_close(server1);
return 0;
}Как видно из кода выше, все интересное происходит именно в обработчиках, где собственно и будет находиться ваша собственная логика, если вдруг решитесь использовать эту библиотеку.
Повторюсь, что весь этот проект, несмотря на всю свою интересность — сырой прототип и тащить в прод подобный код "as-is" точно не стоит.
Собирается только для Linux и только с помощью gcc.
cpp-httplib
https://github.com/yhirose/cpp-httplib
Это уже более зрелая библиотека:
11к строк кода на C++11 и несколько зависимостей от внешних библиотек:
pthreads, brotli, OpenSSL, zlib
реализуют весьма продвинутый HTTP/HTTPS сервер и клиент, причем фактически в одном файле.
Есть поддержка сборки как на Linux так и Windows, причем для второй есть готовый проект для Visual Studio.
Разумеется это не мейнстрим и к качеству есть вопросы, зато все уместилось в очень небольшом коде, без особых ухищрений по миниатюризации и потому вполне читаемому.
Так выглядит сборка тестового сервера, использующего эту библиотеку:
g++ -o server -O2 -std=c++11 -I.. -Wall -Wextra -pthread \ server.cc -DCPPHTTPLIB_OPENSSL_SUPPORT -lssl -lcrypto \ -DCPPHTTPLIB_ZLIB_SUPPORT -lz -DCPPHTTPLIB_BROTLI_SUPPORT \ -lbrotlicommon -lbrotlienc -lbrotlidec
Несложно догадаться по флагам вроде CPPHTTPLIB_ZLIB_SUPPORT, что большая часть зависимостей отключаема.
Еще думаю, заблудиться в 11к строчках кода и одном единственном файле будет проблематично даже унейросетине самых опытных «плюсолюбов».
Так выглядит серверный «Hello, world!»:
#include <httplib.h>
using namespace httplib;
int main(void) {
Server svr;
svr.Get("/hi", [](const Request & /*req*/, Response &res) {
res.set_content("Hello World!", "text/plain");
});
svr.listen("0.0.0.0", 8080);
}В лучших традициях Django или Rails, тут есть маршрутизация запросов и привязка к URL — в данном случае обработчик связывается с урлом /hi.
Вот так выглядит обработка загрузки файлов с помощью формы и POST-запроса:
#include <fstream>
#include <httplib.h>
#include <iostream>
using namespace httplib;
using namespace std;
const char *html = R"(
<form id="formElem">
<input type="file" name="image_file" accept="image/*">
<input type="file" name="text_file" accept="text/*">
<input type="submit">
</form>
<script>
formElem.onsubmit = async (e) => {
e.preventDefault();
let res = await fetch('/post', {
method: 'POST',
body: new FormData(formElem)
});
console.log(await res.text());
};
</script>
)";
int main(void) {
Server svr;
svr.Get("/", [](const Request & /*req*/, Response &res) {
res.set_content(html, "text/html");
});
svr.Post("/post", [](const Request &req, Response &res) {
const auto &image_file = req.form.get_file("image_file");
const auto &text_file = req.form.get_file("text_file");
cout << "image file length: " << image_file.content.length() << endl
<< "image file name: " << image_file.filename << endl
<< "text file length: " << text_file.content.length() << endl
<< "text file name: " << text_file.filename << endl;
{
ofstream ofs(image_file.filename, ios::binary);
ofs << image_file.content;
}
{
ofstream ofs(text_file.filename);
ofs << text_file.content;
}
res.set_content("done", "text/plain");
});
svr.listen("localhost", 1234);
}Разумеется подобный функционал — не откровение, особенно на 2026й год, но блин господа офицеры:
11к строк кода на все красоты!
Теперь переходим к миниатюрным реализациям протокола FTP — для передачи файлов, если кто вдруг забыл.
tiny_ftpserver
https://github.com/adamwym/tiny_ftpserver
Вот такой «игрушечный» проект:
всего 1.5к строк на С++11 от безвестного китайского автора реализуют полнофункциональный FTP/FTPS-сервер:
с chroot, поддержкой локальных и анонимных юзеров и всем прочим.
FTPS это довольно редко встречающееся расширение протокола FTP, с поддержкой шифрования передачи данных. Не набравшее большой популярности ввиду появления SFTP и органичений самого FTP.
Проект использует известную библиотеку libnet, о чем автор забыл сообщить:
apt install libnet1-dev
Cборка происходит с помощью cmake:
mkdir build && cd build cmake ..
Реализация FTP-сервера тут максимально классическая — используется chroot, а использование 21 и 20 портов зашито в код:
.. int socketfd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0); struct sockaddr_in server_addr; memset(&server_addr, 0, sizeof(server_addr)); server_addr.sin_port = htons(21); server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = INADDR_ANY; ..
Все это означает, что запускать сервер придется от суперпользователя:
sudo ./tiny_ftpserver ../tiny_ftpserver.conf
У этого проекта есть один неожиданный нюанс:
на самом деле это.. студенческая работа.
И подобных проектов на Github оказалось великое множество.
Так что далеко не везде в 2026м году забыли что такое высшее техническое образование, что не может не радовать.
fineFTP Server
https://github.com/eclipse-ecal/fineftp-server
Следующий интересный и весьма редкий проект:
FineFTP is a minimal FTP server library for Windows and Unix flavors.
~2k строк на С++14 реализуют FTP-сервер в виде.. библиотеки!
В этом и есть основной прикол — возможность встроить FTP (причем сервер а не клиент) в ваш собственный проект.
Так выглядит код примера, с внедрением FTP-сервера:
#include <fineftp/server.h>
#include <thread>
int main() {
// Create an FTP Server on port 2121. We use 2121 instead of the default port
// 21, as your application would need root privileges to open port 21.
fineftp::FtpServer ftp_server(2121);
// Add the well known anonymous user. Clients can log in using username
// "anonymous" or "ftp" with any password. The user will be able to access
// your C:\ drive and upload, download, create or delete files. On Linux just
// replace "C:\\" with any valid path. FineFTP is designed to be cross-platform.
ftp_server.addUserAnonymous("C:\\", fineftp::Permission::All);
// Start the FTP Server with a thread-pool size of 4.
ftp_server.start(4);
// Prevent the application from exiting immediately
for (;;) std::this_thread::sleep_for(std::chrono::milliseconds(100));
return 0;
}Зачем и для чего такое может быть нужно — другой вопрос, все же обычно работу с файлами в конечном приложении (например обновление прошивки) стараются реализовать в виде клиента и через HTTP/HTTPS.
Но с точки зрения использования все отлично работает:
Это хорошая, взрослая библиотека, с несколькими коммитерами, с историей разработки, которая активно поддерживается и развивается.
Старого цирка с chroot и 21м портом тут нет, поэтому все работает без привилегий суперпользователя — на скриншоте выше как раз видно использование нестандартного порта для работы.
Поддерживается сборка для Linux, MacOS и Windows c приоритетом для последней.
Отличный проект, но далеко не последний в сегодняшней подборке.
rcpd
https://github.com/tenox7/rcpd
Этот проект — привет из далекого и славного прошлого:
This is a modern re-implementation of rcp (remote copy protocol) daemon, originally part berkeley r-commands.
Да, это самый настоящий сервер RCP, всего 300 строк на Golang от знаменитого в узких кругах компьютерных реконструкторов автора Tenox.
RCP это такой устаревший протокол передачи файлов между компьютерами с UNIX, уже мало пригодный для использования в современных реалиях ввиду отсутствия какого-либо шифрования и авторизации.
Крайне актуальный, если имеете дело с устаревшим оборудованием или встраиваемыми системами, которые до сих пор используют именно rcp для загрузки прошивок по сети.
rcpd от Tenox реализует серверную сторону — сервер RCP
К которому подключаются клиенты для загрузки или скачивания файлов.
Так выглядит процесс копирования файла, в качестве клиента тут rcp из пакета GNU Inetutils:
Как видите и клиент и сервер запускаются от суперпользователя — такие были времена, RCP использует 514 порт, который нельзя занять без привилегий.
go build -o rcpd .
Кстати в Makefile проекта есть поддержка кроссплатформенных сборок, с весьма богатым выбором:
Стоит добавить, что протокол RCP сам по себе очень простой и не менялся весь период своего существования, что позволяет подключаться к этому RCP-серверу даже с помощью клиентских программ из 80х и 90х.
За кадром
Детально разобрать удалось лишь малую часть интересных находок, поэтому ниже буквально одной строкой про интересные миниатюрные, точно заслуживающие внимания.
url.c
https://github.com/cozis/url.c/
Парсер строк URL на чистом С и без зависимостей:
This is a small library to parse and manipulate URLs in conformance to RFC 3986 and (most of) the WHATWG specification.
- No allocations
- No dependencies
- The ability to switch between RFC 3986 and WHATWG with a flag
- Relative reference parsing and resolution
- URL normalization
- Doesn't rely on null-terminated strings
LightFTP
https://github.com/hfiref0x/LightFTP
Еще один интересный проект миниатюрного FTP-сервера:
Small x86-32/x64 FTP Server
Поддерживается сборка под Linux/Windows/Mac, сам проект не мертвый и судя по коммитам - развивается.
uftpserver
https://github.com/cpopp/MicroFTPServer
Весьма специфичная реализация FTP-сервера для встраиваемых систем:
Minimal FTP Server that can run on an ESP8266 with MicroPython
Так я впервые узнал о существовании «микропетона» — давно существующего проекта, с огромным количеством поддерживаемого железа и широким функционалом.
Ну и в качестве финального аккорда:
https://github.com/mtheall/ftpd
Реализация FTP-сервера для.. Nintendo Switch!
Это такая игровая консоль для задротов если кто вдруг не в курсе: