Асинхронный IO с epoll и kqueue
Масштабируйте работу с множеством соединений с помощью epoll в Linux и kqueue в BSD или macOS.
«Асинхронный IO с epoll и kqueue» — бесплатный урок C++ Academy на CoddyKit. Это урок 3 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения C++ Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс C++ Academy содержит 4 уроков всего.
Зачем нужен асинхронный ввод-вывод?
Модель с отдельным потоком для каждого соединения не масштабируется до тысяч или миллионов клиентов. Асинхронный ввод-вывод позволяет одному потоку обрабатывать множество сокетов, ожидая готовности любого из них к чтению или записи.
Linux: epoll
epoll — масштабируемый API событий в Linux. Добавьте файловые дескрипторы в экземпляр epoll и ожидайте событий от любого из них.
#include <sys/epoll.h>
int epfd = epoll_create1(0);
epoll_event ev{};
ev.events = EPOLLIN;
ev.data.fd = sock;
epoll_ctl(epfd, EPOLL_CTL_ADD, sock, &ev);Ожидание событий
epoll_wait блокирует выполнение, пока не появятся события, а затем возвращает готовые дескрипторы.
epoll_event events[64];
int n = epoll_wait(epfd, events, 64, -1);
for (int i = 0; i < n; ++i) {
int fd = events[i].data.fd;
handle_io(fd);
}Режимы срабатывания по фронту и по уровню
Есть два режима:
- Срабатывание по уровню (по умолчанию) — epoll продолжает сообщать о событии, пока выполняется условие
- Срабатывание по фронту (
EPOLLET) — сообщает только об изменении состояния; каждый раз необходимо полностью вычитать данные из сокета
macOS и BSD: kqueue
kqueue — эквивалент epoll в BSD, также доступный в macOS. Концептуально они похожи, но используют разные API.
#include <sys/event.h>
int kq = kqueue();
struct kevent ev;
EV_SET(&ev, sock, EVFILT_READ, EV_ADD, 0, 0, nullptr);
kevent(kq, &ev, 1, nullptr, 0, nullptr);Windows: IOCP
Windows использует порты завершения операций ввода-вывода (IOCP) — модель на основе завершения (уведомление после завершения операции), а не модель готовности, используемую epoll и kqueue.
Неблокирующие сокеты
Переведите сокеты в неблокирующий режим с помощью fcntl(fd, F_SETFL, O_NONBLOCK). Иначе чтение и запись могут заблокировать весь цикл обработки событий.
Шаблон цикла обработки событий
Цикл, работающий бесконечно:
- Ожидать готовых событий
- Для каждого события выполнять ввод-вывод, пока операция не заблокируется
- Повторять
Обработка множества клиентов
Один поток epoll может обрабатывать десятки тысяч одновременных соединений — это задача C10K. Современные системы способны работать с миллионами соединений.
Распространённые ошибки
Следите за следующими проблемами:
- Забыли включить неблокирующий режим
- Используете срабатывание по фронту, но не вычитываете сокет полностью
- Не удаляете закрытые файловые дескрипторы из набора epoll
- Допускаете утечки буферов для каждого соединения
Высокоуровневые обёртки
Ручная реализация цикла epoll чревата ошибками. Для промышленного кода используйте libuv, libevent или Boost.Asio — они скрывают различия платформ и предоставляют протестированные циклы ввода-вывода.
Асинхронный ввод-вывод и потоки
Асинхронный ввод-вывод лучше масштабируется, но его сложнее писать. Для серверов с несколькими тысячами соединений модель с отдельным потоком для каждого соединения проще. Выбирайте подход с учётом ожидаемой нагрузки.
Быстрая проверка
Чем отличаются режимы срабатывания по фронту и по уровню в epoll?
Итоги
Асинхронный ввод-вывод поддерживает огромное количество одновременных соединений, обрабатывая множество сокетов в одном потоке. В Linux используется epoll, в BSD и macOS — kqueue, а в Windows — IOCP. Переводите сокеты в неблокирующий режим. В промышленном коде используйте библиотеку (Asio, libuv, libevent), а не пишите цикл обработки событий вручную.
Часто задаваемые вопросы
Урок «Асинхронный IO с epoll и kqueue» бесплатный?
Да — полный текст урока «Асинхронный IO с epoll и kqueue» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс C++ Academy, подпишись на CoddyKit PRO. Курс C++ Academy содержит 4 уроков всего.
Чему я научусь в уроке «Асинхронный IO с epoll и kqueue»?
Масштабируйте работу с множеством соединений с помощью epoll в Linux и kqueue в BSD или macOS. Ты практикуешь C++ Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать C++ Academy?
Предыдущий опыт не требуется. C++ Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 3 из 4.
Сколько времени занимает урок «Асинхронный IO с epoll и kqueue»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке C++ Academy?
Да. Каждый урок C++ Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- API сокетов BSD в C++
- Создание эхо-сервера TCP
- Асинхронный IO с epoll и kqueue
- Использование Boost Asio для современного асинхронного IO