Event loopet
Reagér på læsbare sockets.
Event loopet er en gratis C Academy-lektion på CoddyKit. Dette er lektion 3 af 4. Du kan læse hele lektionen gratis nedenfor — og derefter øve dig praktisk i browseren med en indbygget kodeeditor og en AI-vejleder, der er tilgængelig døgnet rundt. Den er en del af læringsforløbet i C Academy, og dine fremskridt synkroniseres på tværs af nettet og CoddyKit-appen. C Academy-kurset indeholder 4 lektioner i alt.
Serverens kerne
Hændelsesløkken er den motor, der driver en epoll-server. Den venter gentagne gange på klare deskriptorer og sender arbejdet videre til handlere.
Strukturen er altid den samme: Kald epoll_wait(), gennemløb de returnerede hændelser, reagér på hver af dem, og gentag derefter løkken. Alt andet hægter sig på dette skelet.
for (;;) {
int n = epoll_wait(epfd, events, MAX_EVENTS, -1);
for (int i = 0; i < n; i++) handle(&events[i]);
}Kald af epoll_wait
epoll_wait() tager epoll-fd'en, et output-array af epoll_event, arrayets kapacitet og en timeout i millisekunder.
Kaldet blokerer, indtil mindst én deskriptor er klar, eller timeouten udløber, og returnerer, hvor mange hændelser der blev udfyldt i dit array. Kun disse elementer er gyldige.
struct epoll_event events[MAX_EVENTS];
int n = epoll_wait(epfd, events, MAX_EVENTS, -1);
if (n == -1) { perror("epoll_wait"); }Timeout-argumentet
En timeout på -1 blokerer ubegrænset, indtil en hændelse ankommer. Værdien 0 returnerer straks og foretager polling uden at sove.
En positiv værdi begrænser ventetiden. Det er nyttigt, hvis du også skal køre periodiske opgaver som at tømme logge eller udløbe inaktive forbindelser.
int n = epoll_wait(epfd, events, MAX_EVENTS, 1000); /* up to 1s */
if (n == 0) run_periodic_tasks();Tilpasning af hændelsesarrayets størrelse
Arrayets kapacitet begrænser, hvor mange klare hændelser ét epoll_wait()-kald kan rapportere. Hvis flere er klare, returneres resten ved næste kald.
En moderat størrelse som 64 eller 1024 er fin; epoll roterer retfærdigt gennem ventende hændelser på tværs af kald, så ingen sulter.
#define MAX_EVENTS 64
struct epoll_event events[MAX_EVENTS];Videreformidling på den lyttende socket
Inde i løkken skal du først kontrollere, om den klare deskriptor er din lyttende socket. Hvis det er tilfældet, betyder det, at nye forbindelser venter.
Du accepterer dem, sætter dem til ikke-blokerende tilstand og registrerer dem med epoll. Alle andre deskriptorer tilhører eksisterende klienter med data, der skal læses, eller plads, der kan skrives til.
if (events[i].data.fd == listen_fd) {
accept_new_connections(epfd, listen_fd);
} else {
handle_client(epfd, &events[i]);
}Accept af forbindelser i en løkke
Én klar hændelse på den lyttende socket kan betyde, at flere forbindelser venter. Kør en løkke omkring accept(), indtil den returnerer EAGAIN.
Det er nødvendigt i kantudløst tilstand og god praksis overalt, så du ikke lader klienter vente til næste opvågning.
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);
}Håndtering af læsbare hændelser
Når EPOLLIN udløses på en klient, skal du læse fra den. I niveauudløst tilstand er ét recv()-kald pr. opvågning acceptabelt.
En returværdi på 0 betyder, at klienten lukkede forbindelsen: Ryd op efter den. En negativ returværdi sammen med EAGAIN betyder, at du indtil videre har tømt alle tilgængelige data.
ssize_t r = recv(fd, buf, sizeof buf, 0);
if (r == 0) { close_conn(epfd, fd); }
else if (r > 0) { process(buf, r); }Tømning i kantudløst tilstand
Med EPOLLET skal du læse, indtil recv() returnerer EAGAIN. Kernen giver dig kun besked ved overgangen til læsbar tilstand, så resterende bytes ellers ville gå tabt, indtil tilstanden ændres igen.
Pak læsningen ind i en løkke, og bryd kun ud ved EAGAIN eller slutningen på datastrømmen.
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; } }
}Håndtering af skrivbare hændelser
EPOLLOUT udløses, når en socket kan modtage flere udgående data. Du ønsker kun dette, når du har bytes i bufferen, som tidligere ikke blev sendt helt.
Tøm din buffer; når den er tom, skal du med EPOLL_CTL_MOD skifte interessen tilbage til kun EPOLLIN for at undgå en konstant strøm af skriveklare hændelser.
if (events[i].events & EPOLLOUT) {
flush_pending(fd);
if (buffer_empty(fd)) watch_read_only(epfd, fd);
}Håndtering af afbrudte ventekald
epoll_wait() kan returnere -1 med errno == EINTR, hvis et signal afbryder kaldet. Det er ikke en reel fejl; prøv blot igen.
Robuste løkker fortsætter ved EINTR og betragter kun andre fejlkoder som fatale. Hvis du glemmer dette, kan serveren gå ned, første gang den modtager et signal.
int n = epoll_wait(epfd, events, MAX_EVENTS, -1);
if (n == -1) {
if (errno == EINTR) continue;
perror("epoll_wait"); break;
}Én løkke, mange klienter
Saml det hele, så en enkelt tråd gennemløber klare deskriptorer for evigt: acceptér, læs, skriv, luk, gentag.
Fordi tråden sover i epoll_wait(), når der ikke er noget arbejde, og kun behandler klart arbejde, når den er aktiv, kan dette design uden problemer håndtere titusindvis af samtidige forbindelser.
Hurtigt tjek
Test din forståelse af hændelsesløkken.
Opsummering
Hændelsesløkken kalder epoll_wait(), gennemløber de klare hændelser og sender dem videre: acceptér på den lyttende socket, læs ved EPOLLIN, tøm bufferen ved EPOLLOUT, og ryd op ved afbrydelse.
Kør accept- og læseoperationer i løkker, prøv igen ved EINTR, og tøm helt i EPOLLET-tilstand. Nu samler vi en komplet echo-server.
Lær C med en AI-underviser — gratis
Skriv og kør rigtig kode i din browser, få øjeblikkelig hjælp fra en AI-underviser døgnet rundt, og fortsæt, hvor du slap, på web eller i appen.
- Kurser
- 39
- Lektioner
- 144
Ofte stillede spørgsmål
Er lektionen “Event loopet” gratis?
Ja — hele teksten til “Event loopet” kan læses gratis her på nettet. Hvis du vil øve dig interaktivt med en indbygget kodeeditor og en AI-vejleder døgnet rundt og få adgang til resten af C Academy-kurset, skal du opgradere til CoddyKit PRO. C Academy-kurset indeholder 4 lektioner i alt.
Hvad lærer jeg i “Event loopet”?
Reagér på læsbare sockets. Du øver dig i C Academy med praktisk kode, som du kører direkte i browseren, og en AI-vejleder døgnet rundt besvarer dine spørgsmål, mens du arbejder dig gennem lektionen.
Skal jeg have erfaring for at begynde på C Academy?
Der kræves ingen tidligere erfaring. C Academy på CoddyKit er tilrettelagt for både begyndere og øvede, så du kan starte her eller fra begyndelsen og lære i dit eget tempo. Dette er lektion 3 af 4.
Hvor lang tid tager lektionen “Event loopet”?
De fleste CoddyKit-lektioner tager cirka 5–10 minutter. Hver lektion er kort og interaktiv, så du gør løbende fremskridt og kan fortsætte, hvor du slap – på både web og app.
Kan jeg skrive og køre kode i denne C Academy-lektion?
Ja. Alle C Academy-lektioner har en indbygget kodeeditor, så du kan skrive og køre rigtig kode direkte i din browser og få øjeblikkelig feedback fra AI – uden lokal opsætning.