C Academy · Lekcja

Konfiguracja epoll

Utworzy Pan/Pani zbiór epoll i zarejestruje w nim deskryptory.

Lekcja 2 z 413 kroki

Konfiguracja epoll to bezpłatna lekcja C Academy na CoddyKit. To lekcja 2 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.

Tworzenie instancji epoll

Wszystko zaczyna się od instancji epoll, która sama jest deskryptorem pliku. Utwórz ją za pomocą epoll_create1().

Argument to pole flag; przekaż 0, aby użyć domyślnego działania, albo EPOLL_CLOEXEC, aby deskryptor był automatycznie zamykany podczas exec(). Zwrócony deskryptor fd przekazujesz do każdego innego wywołania epoll.

int epfd = epoll_create1(EPOLL_CLOEXEC);
if (epfd == -1) { perror("epoll_create1"); exit(1); }

epoll_create1 a epoll_create

Starsza funkcja epoll_create(int size) przyjmowała wskazówkę dotyczącą rozmiaru, ale jądro obecnie ją ignoruje; jedynym wymaganiem było, aby wartość była dodatnia.

Należy preferować epoll_create1(): przyjmuje flagi zamiast pozbawionego znaczenia rozmiaru i pozwala atomowo zażądać EPOLL_CLOEXEC, unikając osobnego wywołania fcntl().

/* legacy form, size arg ignored by kernel */
int epfd = epoll_create(1);

Struktura epoll_event

Monitorowane zdarzenia i ich wyniki są wyrażane za pomocą struct epoll_event. Struktura zawiera maskę bitową events oraz unię data.

Unia data przechowuje dowolną wartość, którą ma zostać zwrócona po wystąpieniu zdarzenia: najczęściej data.fd, ale może to być także data.ptr wskazujące na przydzielony przez Państwa obiekt połączenia.

struct epoll_event ev;
ev.events = EPOLLIN;
ev.data.fd = listen_fd;

Rejestrowanie za pomocą EPOLL_CTL_ADD

epoll_ctl() zarządza listą monitorowanych zdarzeń. Operacji EPOLL_CTL_ADD należy użyć, aby rozpocząć monitorowanie deskryptora.

Przekazują Państwo deskryptor epoll, operację, docelowy deskryptor oraz wskaźnik do epoll_event. Od tego momentu epoll będzie zgłaszać gotowość tego deskryptora.

struct epoll_event ev = { .events = EPOLLIN, .data.fd = listen_fd };
if (epoll_ctl(epfd, EPOLL_CTL_ADD, listen_fd, &ev) == -1)
    perror("epoll_ctl: add");

Flagi zdarzeń: EPOLLIN i EPOLLOUT

Maska events określa, co Państwa interesuje. EPOLLIN oznacza, że deskryptor jest gotowy do odczytu, a EPOLLOUT — że jest gotowy do zapisu.

Zwykle monitoruje się EPOLLIN na gnieździe nasłuchującym, aby akceptować połączenia, oraz na gniazdach klientów, aby odczytywać dane. EPOLLOUT należy dodawać tylko wtedy, gdy mają Państwo w buforze dane, których nie udało się w całości wysłać.

ev.events = EPOLLIN | EPOLLOUT;

Flagi błędu i rozłączenia

Jądro zawsze zgłasza określone warunki, nawet jeśli nie zostały zażądane: EPOLLERR w przypadku błędów, EPOLLHUP w przypadku rozłączenia oraz EPOLLRDHUP w przypadku częściowego zamknięcia połączenia przez drugą stronę.

Należy sprawdzać te flagi w procedurze obsługi; zignorowanie EPOLLHUP na zamkniętym gnieździe prowadzi do nieustannego wykonywania pętli zdarzeń.

if (ev.events & (EPOLLERR | EPOLLHUP)) {
    close(ev.data.fd);
    continue;
}

Modyfikowanie monitorowanych zdarzeń za pomocą EPOLL_CTL_MOD

Po zarejestrowaniu deskryptora można zmienić jego maskę zdarzeń bez usuwania go. Należy użyć EPOLL_CTL_MOD.

Typowy schemat wygląda następująco: połączenie zwykle monitoruje tylko EPOLLIN, następnie przełącza się na EPOLLIN | EPOLLOUT, gdy zapełni się bufor wysyłania, a po jego opróżnieniu wraca do poprzedniej konfiguracji.

ev.events = EPOLLIN | EPOLLOUT;
ev.data.fd = conn_fd;
epoll_ctl(epfd, EPOLL_CTL_MOD, conn_fd, &ev);

Usuwanie za pomocą EPOLL_CTL_DEL

Po zamknięciu połączenia należy przestać je monitorować za pomocą EPOLL_CTL_DEL. Ostatni argument typu epoll_event jest ignorowany i w nowszych jądrach może mieć wartość NULL.

Proszę pamiętać, że zamknięcie deskryptora automatycznie usuwa go ze wszystkich list monitorowania epoll, ale jawne usunięcie przed zamknięciem ułatwia kontrolowanie stanu programu.

epoll_ctl(epfd, EPOLL_CTL_DEL, conn_fd, NULL);
close(conn_fd);

Tryb poziomowy a tryb krawędziowy

Domyślnie epoll działa w trybie poziomowym: dopóki deskryptor pozostaje gotowy do odczytu, każde wywołanie epoll_wait() go zgłasza. To wybaczające błędy i łatwe w użyciu rozwiązanie.

Dodanie flagi EPOLLET włącza tryb krawędziowy: powiadomienie jest wysyłane tylko wtedy, gdy zmieni się stan gotowości, dlatego należy całkowicie opróżnić gniazdo w pętli aż do uzyskania EAGAIN.

ev.events = EPOLLIN | EPOLLET;  /* edge-triggered */
epoll_ctl(epfd, EPOLL_CTL_ADD, conn_fd, &ev);

Przechowywanie wskaźnika kontekstu

Zamiast data.fd mogą Państwo przechowywać w data.ptr wskaźnik do struktury przypisanej do konkretnego połączenia. Po wystąpieniu zdarzenia wskaźnik ten jest zwracany bezpośrednio, bez potrzeby korzystania z tabeli wyszukiwania.

Należy tylko pamiętać o unii: jeśli ustawią Państwo data.ptr, nie można jednocześnie odczytywać data.fd z tego samego zdarzenia.

struct conn *c = malloc(sizeof *c);
c->fd = conn_fd;
ev.events = EPOLLIN;
ev.data.ptr = c;
epoll_ctl(epfd, EPOLL_CTL_ADD, conn_fd, &ev);

Sprzątanie zasobów

Instancja epoll jest po prostu deskryptorem pliku, dlatego po wyłączeniu serwera należy ją zwolnić za pomocą close().

Zamknięcie deskryptora epoll zwalnia jądrową listę monitorowanych zdarzeń. Wszystkie nadal otwarte monitorowane gniazda pozostają otwarte; należy zamknąć je osobno, aby zwolnić zajmowane zasoby.

close(epfd);

Szybkie sprawdzenie

Sprawdź swoją znajomość interfejsu API konfiguracji epoll.

Podsumowanie

Instancję tworzy się za pomocą epoll_create1(), a następnie zarządza monitorowanymi zdarzeniami przez epoll_ctl(), używając operacji ADD, MOD i DEL. Każda struktura struct epoll_event zawiera maskę events oraz unię data.

Tryb poziomowy zapewnia prostotę, natomiast EPOLLET pozwala użyć trybu krawędziowego i uzyskać większą wydajność. Następnie wykorzystamy te elementy w pętli zdarzeń.

Bezpłatny start

Ucz się C dzięki korepetycjom AI — za darmo

Pisz i uruchamiaj kod w przeglądarce, otrzymuj natychmiastową pomoc od korepetytora AI dostępnego 24/7 i kontynuuj naukę w sieci lub w aplikacji.

Kursy
39
Lekcje
144

Często zadawane pytania

Czy lekcja „Konfiguracja epoll” jest bezpłatna?

Tak — pełny tekst „Konfiguracja epoll” 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 „Konfiguracja epoll”?

Utworzy Pan/Pani zbiór epoll i zarejestruje w nim deskryptory. Ć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 2 z 4.

Ile czasu zajmuje lekcja „Konfiguracja epoll”?

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. Blokujące a nieblokujące I/O
  2. Konfiguracja epoll
  3. Pętla zdarzeń
  4. Prosty serwer echo
← Powrót do C Academy