De event loop
Reageer op leesbare sockets.
De event loop is een gratis C Academy-les op CoddyKit. Dit is les 3 van 4. Je kunt de volledige les hieronder gratis lezen en daarna in de browser praktisch oefenen met een ingebouwde code-editor en een AI-begeleider die 24/7 beschikbaar is. Deze les maakt deel uit van het leertraject C Academy. Je voortgang wordt gesynchroniseerd op het web en in de CoddyKit-app. De cursus C Academy bevat in totaal 4 lessen.
Het hart van de server
De gebeurtenislus is de motor van een epoll-server. Deze wacht herhaaldelijk op descriptors die gereed zijn en stuurt het werk door naar handlers.
De vorm is altijd hetzelfde: roep epoll_wait() aan, doorloop de geretourneerde gebeurtenissen, handel elke gebeurtenis af en begin daarna opnieuw. Al het andere sluit op dit geraamte aan.
for (;;) {
int n = epoll_wait(epfd, events, MAX_EVENTS, -1);
for (int i = 0; i < n; i++) handle(&events[i]);
}epoll_wait aanroepen
epoll_wait() neemt de epoll-fd, een uitvoerarray van epoll_event, de capaciteit daarvan en een time-out in milliseconden aan.
De functie blokkeert totdat ten minste één descriptor gereed is (of de time-out verstrijkt) en retourneert hoeveel gebeurtenissen in je array zijn geplaatst. Alleen die vermeldingen zijn geldig.
struct epoll_event events[MAX_EVENTS];
int n = epoll_wait(epfd, events, MAX_EVENTS, -1);
if (n == -1) { perror("epoll_wait"); }Het time-outargument
Een time-out van -1 blokkeert onbeperkt totdat er een gebeurtenis binnenkomt. Een waarde van 0 retourneert onmiddellijk en controleert zonder te slapen.
Een positieve waarde begrenst hoe lang je wacht. Dat is handig als je ook periodieke taken moet uitvoeren, zoals logboeken leegschrijven of inactieve verbindingen laten verlopen.
int n = epoll_wait(epfd, events, MAX_EVENTS, 1000); /* up to 1s */
if (n == 0) run_periodic_tasks();De gebeurtenisarray dimensioneren
De capaciteit van de array begrenst hoeveel gereedstaande gebeurtenissen één aanroep van epoll_wait() kan rapporteren. Als er meer gereed zijn, worden de overige bij de volgende aanroep geretourneerd.
Een bescheiden grootte, zoals 64 of 1024, is prima; epoll doorloopt de wachtende gebeurtenissen eerlijk verdeeld over de aanroepen, zodat niets wordt verhongerd.
#define MAX_EVENTS 64
struct epoll_event events[MAX_EVENTS];Gebeurtenissen op de luistersocket afhandelen
Controleer in de lus eerst of de gereedstaande descriptor je luistersocket is. Zo ja, dan betekent dit dat er nieuwe verbindingen wachten.
Accepteer deze, stel ze in op niet-blokkerend en registreer ze bij epoll. Alle andere descriptors zijn bestaande clients met gegevens om te lezen of ruimte om naar te schrijven.
if (events[i].data.fd == listen_fd) {
accept_new_connections(epfd, listen_fd);
} else {
handle_client(epfd, &events[i]);
}Verbindingen in een lus accepteren
Eén gereedheidsgebeurtenis op de luistersocket kan betekenen dat er meerdere verbindingen wachten. Blijf accept() aanroepen totdat deze EAGAIN retourneert.
Dit is essentieel in de flankgestuurde modus en overal een goede gewoonte, zodat je clients niet tot de volgende keer dat de lus wordt geactiveerd laat wachten.
for (;;) {
int c = accept(listen_fd, NULL, NULL);
if (c == -1) { if (errno == EAGAIN) break; else break; }
set_nonblocking(c);
add_to_epoll(epfd, c);
}Leesbare gebeurtenissen afhandelen
Wanneer EPOLLIN voor een client optreedt, lees je ervan. In de niveaugestuurde modus is één recv() per activering voldoende.
Een retourwaarde van 0 betekent dat de client de verbinding heeft gesloten: ruim deze op. Een negatieve retourwaarde met EAGAIN betekent dat je alle momenteel beschikbare gegevens hebt gelezen.
ssize_t r = recv(fd, buf, sizeof buf, 0);
if (r == 0) { close_conn(epfd, fd); }
else if (r > 0) { process(buf, r); }Leeglezen in de flankgestuurde modus
Met EPOLLET moet je lezen totdat recv() EAGAIN retourneert. De kernel meldt je alleen de overgang naar leesbaarheid, dus achtergebleven bytes zouden verloren gaan tot de volgende verandering.
Wikkel het lezen in een lus en breek alleen af bij EAGAIN of het einde van de gegevensstroom.
for (;;) {
ssize_t r = recv(fd, buf, sizeof buf, 0);
if (r > 0) process(buf, r);
else if (r == 0) { close_conn(epfd, fd); break; }
else { if (errno == EAGAIN) break; else { close_conn(epfd, fd); break; } }
}Beschrijfbare gebeurtenissen afhandelen
EPOLLOUT treedt op wanneer een socket meer uitgaande gegevens kan accepteren. Je wilt dit alleen wanneer je gebufferde bytes hebt die eerder niet volledig konden worden verzonden.
Schrijf je buffer leeg; zodra deze leeg is, schakel je met EPOLL_CTL_MOD de gewenste gebeurtenissen terug naar alleen EPOLLIN om een constante stroom van schrijfklare meldingen te voorkomen.
if (events[i].events & EPOLLOUT) {
flush_pending(fd);
if (buffer_empty(fd)) watch_read_only(epfd, fd);
}Onderbroken wachttijden afhandelen
epoll_wait() kan -1 retourneren met errno == EINTR als een signaal de aanroep onderbreekt. Dit is geen echte fout; probeer het gewoon opnieuw.
Robuuste lussen gaan door bij EINTR en behandelen alleen andere foutcodes als fataal. Als je dit vergeet, kan een server crashen zodra deze voor het eerst een signaal ontvangt.
int n = epoll_wait(epfd, events, MAX_EVENTS, -1);
if (n == -1) {
if (errno == EINTR) continue;
perror("epoll_wait"); break;
}Eén lus, veel clients
Voeg alles samen en één thread doorloopt voortdurend de gereedstaande descriptors: accepteren, lezen, schrijven, sluiten en herhalen.
Omdat de thread in epoll_wait() slaapt wanneer er niets te doen is en alleen gereed werk verwerkt wanneer het druk is, kan dit ontwerp probleemloos tienduizenden gelijktijdige verbindingen afhandelen.
Korte controle
Test hoe goed je de gebeurtenislus begrijpt.
Samenvatting
De gebeurtenislus roept epoll_wait() aan, doorloopt de gereedstaande gebeurtenissen en stuurt ze door: accepteren op de luistersocket, lezen bij EPOLLIN, buffers leegschrijven bij EPOLLOUT en opruimen bij een verbreking.
Voer acceptaties en leesbewerkingen in een lus uit, probeer het opnieuw bij EINTR en lees volledig leeg bij EPOLLET. Vervolgens bouwen we een complete echo-server.
Leer C met een AI-tutor — gratis
Schrijf echte code en voer die uit in je browser, krijg direct hulp van een AI-tutor die 24/7 beschikbaar is en ga verder waar je gebleven bent op het web of in de app.
- Cursussen
- 39
- Lessen
- 144
Veelgestelde vragen
Is de les “De event loop” gratis?
Ja — de volledige tekst van “De event loop” kun je hier gratis op het web lezen. Als je interactief wilt oefenen met een ingebouwde code-editor en een AI-begeleider die 24/7 beschikbaar is, en de rest van de cursus C Academy wilt ontgrendelen, kun je upgraden naar CoddyKit PRO. De cursus C Academy bevat in totaal 4 lessen.
Wat leer ik in “De event loop”?
Reageer op leesbare sockets. Je oefent met C Academy door code rechtstreeks in de browser uit te voeren. Een AI-begeleider die 24/7 beschikbaar is beantwoordt je vragen terwijl je de les doorwerkt.
Heb ik ervaring nodig om met C Academy te beginnen?
Ervaring vooraf is niet nodig. C Academy op CoddyKit is opgebouwd voor beginners tot gevorderden, zodat je hier of bij het begin kunt starten en in je eigen tempo kunt leren. Dit is les 3 van 4.
Hoe lang duurt de les “De event loop”?
De meeste lessen van CoddyKit duren ongeveer 5–10 minuten. Elke les is kort en interactief, zodat je gestaag vooruitgaat en op het web en in de app precies verdergaat waar je was gebleven.
Kan ik code schrijven en uitvoeren in deze les over C Academy?
Ja. Elke les over C Academy bevat een ingebouwde code-editor, zodat je rechtstreeks in je browser echte code kunt schrijven en uitvoeren en direct feedback van AI krijgt — lokale installatie is niet nodig.