0Pricing
C++ Academy · Lekcja

Asynchroniczne wejście/wyjście z epoll i kqueue

Obsługuj wiele połączeń za pomocą epoll w systemie Linux oraz kqueue w BSD lub macOS

Asynchroniczne wejście/wyjście z epoll i kqueue to bezpłatna lekcja C++ Academy na CoddyKit. To lekcja 3 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej C++ Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs C++ Academy zawiera 4 lekcji w sumie.

Dlaczego asynchroniczne wejście/wyjście?

Model z jednym wątkiem na połączenie nie skaluje się do tysięcy ani milionów klientów. Asynchroniczne wejście/wyjście pozwala jednemu wątkowi obsługiwać wiele gniazd, oczekując, aż któreś z nich będzie gotowe do odczytu lub zapisu.

Linux: epoll

epoll to skalowalne API zdarzeń systemu Linux. Dodaj deskryptory plików do instancji epoll i czekaj na zdarzenia dotyczące dowolnego z nich.

#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);

Oczekiwanie na zdarzenia

epoll_wait blokuje wykonanie do momentu pojawienia się zdarzeń, a następnie zwraca gotowe deskryptory.

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);
}

Wyzwalanie krawędziowe a poziomowe

Dostępne są dwa tryby:

  • Wyzwalanie poziomowe (domyślne) — epoll nadal zgłasza zdarzenia, dopóki warunek jest spełniony
  • Wyzwalanie krawędziowe (EPOLLET) — zgłasza zdarzenie tylko przy zmianie stanu; za każdym razem trzeba całkowicie opróżnić gniazdo

macOS i BSD: kqueue

kqueue jest odpowiednikiem epoll w systemach BSD i jest również dostępne w macOS. Koncepcyjnie mechanizmy są podobne, ale korzystają z innego 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

System Windows korzysta z portów zakończenia operacji wejścia/wyjścia (IOCP) — modelu opartego na zakończeniu operacji (powiadomienie po jej wykonaniu), a nie na gotowości, jak w epoll/kqueue.

Gniazda nieblokujące

Ustaw gniazda w tryb nieblokujący za pomocą fcntl(fd, F_SETFL, O_NONBLOCK). W przeciwnym razie odczyty i zapisy mogą zablokować całą pętlę zdarzeń.

Wzorzec pętli zdarzeń

Pętla działająca w nieskończoność:

  1. Czekaj na gotowe zdarzenia
  2. Dla każdego zdarzenia wykonuj operacje wejścia/wyjścia, dopóki nie doszłoby do blokowania
  3. Powtarzaj

Obsługa wielu klientów

Pojedynczy wątek epoll może obsługiwać dziesiątki tysięcy jednoczesnych połączeń — to problem C10K. Współczesne systemy obsługują nawet miliony połączeń.

Typowe pułapki

Zwróć uwagę na:

  • zapomnienie o ustawieniu trybu nieblokującego
  • użycie wyzwalania krawędziowego bez opróżniania gniazda
  • nieusuwanie zamkniętych deskryptorów z zestawu epoll
  • wycieki buforów dla poszczególnych połączeń

Abstrakcje wyższego poziomu

Samodzielne napisanie pętli epoll łatwo prowadzi do błędów. W kodzie produkcyjnym użyj libuv, libevent lub Boost.Asio — biblioteki te ukrywają różnice między platformami i udostępniają przetestowane pętle wejścia/wyjścia.

Asynchroniczne wejście/wyjście a wątki

Asynchroniczne wejście/wyjście lepiej się skaluje, ale jest trudniejsze w implementacji. W przypadku serwerów z kilkoma tysiącami połączeń model z jednym wątkiem na połączenie jest prostszy. Wybierz rozwiązanie na podstawie przewidywanego obciążenia.

Szybkie sprawdzenie

Czym różnią się tryby wyzwalania krawędziowego i poziomowego w epoll?

Podsumowanie

Asynchroniczne wejście/wyjście skaluje się do ogromnej liczby jednoczesnych połączeń, obsługując wiele gniazd w jednym wątku. Linux korzysta z epoll, BSD/macOS z kqueue, a Windows z IOCP. Ustaw gniazda w tryb nieblokujący. W kodzie produkcyjnym użyj biblioteki (Asio, libuv, libevent) zamiast ręcznie pisać pętlę zdarzeń.

Często zadawane pytania

Czy lekcja „Asynchroniczne wejście/wyjście z epoll i kqueue” jest bezpłatna?

Tak — pełny tekst „Asynchroniczne wejście/wyjście z epoll i kqueue” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu C++ Academy, przejdź na CoddyKit PRO. Kurs C++ Academy zawiera 4 lekcji w sumie.

Co nauczysz się w „Asynchroniczne wejście/wyjście z epoll i kqueue”?

Obsługuj wiele połączeń za pomocą epoll w systemie Linux oraz kqueue w BSD lub macOS Ćwiczysz C++ Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć C++ Academy?

Nie wymagamy żadnego doświadczenia. C++ Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 3 z 4.

Ile czasu zajmuje lekcja „Asynchroniczne wejście/wyjście z epoll i kqueue”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji C++ Academy?

Tak. Każda lekcja C++ Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. API gniazd BSD w C++
  2. Budowa serwera echa TCP
  3. Asynchroniczne wejście/wyjście z epoll i kqueue
  4. Nowoczesne asynchroniczne wejście/wyjście z Boost Asio
← Powrót do C++ Academy