Un semplice server echo
Serva molti client contemporaneamente.
Un semplice server echo è una lezione C Academy gratuita su CoddyKit. Questa è la lezione 4 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento C Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso C Academy include 4 lezioni in totale.
Cosa realizzeremo
Un echo server accetta connessioni TCP e restituisce tutti i byte inviati dal client. È l'equivalente di "hello world" nella programmazione di rete.
Lo costruiremo con epoll, in modo che un singolo thread possa servire molti client contemporaneamente. I componenti sono: un socket in ascolto, il ciclo epoll e la gestione della lettura e della successiva scrittura per ogni client.
Creazione del socket in ascolto
Inizi con socket() per creare un endpoint TCP IPv4. La terna è AF_INET, SOCK_STREAM e il protocollo 0.
La chiamata restituisce un descrittore di file che assoceremo a un indirizzo, imposteremo in modalità non bloccante e infine registreremo con epoll. Verifichi il valore -1 dopo ogni chiamata di sistema.
int listen_fd = socket(AF_INET, SOCK_STREAM, 0);
if (listen_fd == -1) { perror("socket"); exit(1); }Riutilizzo dell'indirizzo
Prima di associare il socket a un indirizzo, imposti SO_REUSEADDR con setsockopt(). In questo modo il server può riavviarsi e associarsi nuovamente alla stessa porta senza attendere la scadenza dello stato TIME_WAIT.
Senza questa opzione, un riavvio rapido spesso fallisce con EADDRINUSE, una sorpresa frustrante durante lo sviluppo.
int yes = 1;
setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes);Associazione a una porta
Compili una struct sockaddr_in con famiglia, porta e indirizzo. Utilizzi htons() per la porta e INADDR_ANY per ascoltare su tutte le interfacce.
Quindi chiami bind() per associare il socket a quell'indirizzo. htons converte l'ordine dei byte dell'host nell'ordine dei byte di rete, come richiesto.
struct sockaddr_in addr = {0};
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(8080);
bind(listen_fd, (struct sockaddr*)&addr, sizeof addr);Ascolto e modalità non bloccante
Chiami listen() per impostare il socket in modalità passiva e definire una coda per le connessioni in attesa. SOMAXCONN richiede il massimo supportato dal sistema.
Quindi imposti il socket in modalità non bloccante, affinché accept() non blocchi mai il ciclo degli eventi. A questo punto è pronto per essere registrato con epoll.
listen(listen_fd, SOMAXCONN);
set_nonblocking(listen_fd);Registrazione del socket in ascolto
Crei l'istanza epoll e aggiunga il socket in ascolto con EPOLLIN. Un evento di lettura su questo socket significa che un nuovo client è in attesa di essere accettato.
Memorizzi il fd in data.fd, così potremo riconoscere il socket in ascolto all'interno del ciclo.
int epfd = epoll_create1(0);
struct epoll_event ev = { .events = EPOLLIN, .data.fd = listen_fd };
epoll_ctl(epfd, EPOLL_CTL_ADD, listen_fd, &ev);Accettazione di un client
Quando il socket in ascolto è leggibile, ripeta accept() finché non restituisce EAGAIN. Imposti ogni nuovo socket client in modalità non bloccante e lo registri per EPOLLIN.
Da questo momento epoll ci segnalerà ogni volta che il client invia dati che possiamo restituire.
int c = accept(listen_fd, NULL, NULL);
if (c != -1) {
set_nonblocking(c);
struct epoll_event cev = { .events = EPOLLIN, .data.fd = c };
epoll_ctl(epfd, EPOLL_CTL_ADD, c, &cev);
}La logica dell'echo
Per un client pronto, esegua recv() in un buffer. Se riceve dei byte, li rimandi immediatamente con send().
Questa semplice sequenza di lettura e scrittura costituisce l'echo. In produzione memorizzerebbe i byte non inviati in un buffer, ma per questa dimostrazione supponiamo che la piccola risposta entri nel buffer di invio.
char buf[4096];
ssize_t r = recv(fd, buf, sizeof buf, 0);
if (r > 0) {
send(fd, buf, r, 0);
}Rilevamento della disconnessione
Un valore restituito da recv() pari a 0 significa che il client ha eseguito una chiusura ordinata. Un valore negativo associato a qualcosa di diverso da EAGAIN indica un errore reale.
In entrambi i casi, rimuova il descrittore da epoll e lo chiuda con close() per liberare le risorse e interrompere ulteriori notifiche.
if (r == 0 || (r < 0 && errno != EAGAIN)) {
epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL);
close(fd);
}Il ciclo completo
Combini i componenti: attenda gli eventi, distingua se il descrittore è quello in ascolto o quello di un client e agisca di conseguenza.
Questo ciclo compatto è un echo server concorrente perfettamente funzionante: un thread, molti client, nessun thread per connessione.
for (;;) {
int n = epoll_wait(epfd, events, MAX_EVENTS, -1);
for (int i = 0; i < n; i++) {
if (events[i].data.fd == listen_fd) accept_clients();
else echo_or_close(events[i].data.fd);
}
}Test e prossimi passi
Compili su Linux e si connetta con nc localhost 8080: tutto ciò che digita verrà restituito. Apra diversi terminali per verificare la concorrenza.
Per renderlo più robusto: gestisca gli invii parziali con un buffer, gestisca EPOLLOUT, passi a EPOLLET con lo svuotamento completo e gestisca EPOLLRDHUP per le chiusure parziali.
Verifica rapida
Verifichi la Sua comprensione del funzionamento dell'echo server.
Riepilogo
Ha creato un echo server con epoll: creare il socket, impostare SO_REUSEADDR, effettuare il bind, metterlo in ascolto e impostarlo in modalità non bloccante. Registri il listener, accetti i client in un ciclo e rimandi i dati ricevuti con recv()/send().
Gestisca un valore restituito pari a 0 come una disconnessione e chiuda tutto correttamente. Da questa struttura di base può sviluppare un server di rete single-thread ad alte prestazioni.
Domande Frequenti
La lezione «Un semplice server echo» è gratuita?
Sì — il testo completo di «Un semplice server echo» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso C Academy, passa a CoddyKit PRO. Il corso C Academy include 4 lezioni in totale.
Cosa imparerò in «Un semplice server echo»?
Serva molti client contemporaneamente. Eserciti C Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.
Ho bisogno di esperienza per iniziare C Academy?
Non è richiesta alcuna esperienza precedente. C Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 4 di 4.
Quanto tempo richiede la lezione «Un semplice server echo»?
La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.
Posso scrivere ed eseguire codice in questa lezione C Academy?
Sì. Ogni lezione C Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.
Tutte le lezioni di questo corso
- I/O bloccante e non bloccante
- Configurare epoll
- Il ciclo di eventi
- Un semplice server echo