Un servidor de eco sencillo
Atienda a muchos clientes a la vez
Un servidor de eco sencillo es una lección gratuita de C Academy en CoddyKit. Esta es la lección 4 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de C Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de C Academy incluye 4 lecciones en total.
Qué vamos a construir
Un servidor de eco acepta conexiones TCP y devuelve los mismos bytes que envía un cliente. Es el «hola mundo» de la programación de redes.
Lo construiremos sobre epoll para que un único subproceso atienda a muchos clientes a la vez. Las piezas son: un socket de escucha, el bucle de epoll y la gestión de lectura y escritura de cada cliente.
Creación del socket de escucha
Comience con socket() para crear un extremo TCP IPv4. La combinación es AF_INET, SOCK_STREAM y el protocolo 0.
Esto devuelve un descriptor de archivo que vincularemos, configuraremos como no bloqueante y finalmente registraremos en epoll. Compruebe si se devuelve -1 en cada llamada al sistema.
int listen_fd = socket(AF_INET, SOCK_STREAM, 0);
if (listen_fd == -1) { perror("socket"); exit(1); }Reutilización de la dirección
Antes de vincular el socket, establezca SO_REUSEADDR con setsockopt(). Esto permite que el servidor se reinicie y vuelva a vincularse al mismo puerto sin tener que esperar a que termine el estado TIME_WAIT.
Sin esta opción, un reinicio rápido suele fallar con EADDRINUSE, una sorpresa frustrante durante el desarrollo.
int yes = 1;
setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes);Vinculación a un puerto
Rellene un struct sockaddr_in con la familia, el puerto y la dirección. Use htons() para el puerto y INADDR_ANY para escuchar en todas las interfaces.
Después, llame a bind() para asociar el socket a esa dirección. htons convierte el orden de bytes del host al orden de bytes de red, que es obligatorio.
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);Escucha y configuración como no bloqueante
Llame a listen() para marcar el socket como pasivo y establecer una cola para las conexiones pendientes. SOMAXCONN solicita el máximo del sistema.
Después, configure el socket como no bloqueante para que accept() nunca bloquee el bucle de eventos. Ahora está listo para registrarlo en epoll.
listen(listen_fd, SOMAXCONN);
set_nonblocking(listen_fd);Registro del socket de escucha
Cree la instancia de epoll y añada el socket de escucha con EPOLLIN. Un evento de lectura en este socket significa que hay un nuevo cliente esperando para ser aceptado.
Guardamos el fd en data.fd para poder reconocer el socket de escucha dentro del bucle.
int epfd = epoll_create1(0);
struct epoll_event ev = { .events = EPOLLIN, .data.fd = listen_fd };
epoll_ctl(epfd, EPOLL_CTL_ADD, listen_fd, &ev);Aceptación de un cliente
Cuando el socket de escucha se pueda leer, repita accept() hasta EAGAIN. Configure cada nuevo socket de cliente como no bloqueante y regístrelo para EPOLLIN.
A partir de ese momento, epoll nos avisará cada vez que el cliente envíe datos que podamos devolver.
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 lógica del eco
Para un cliente listo, use recv() para leer en un búfer. Si recibe bytes, devuelva esos mismos bytes directamente con send().
Esta sencilla lectura seguida de escritura es el eco. En producción tendría que almacenar en búfer los bytes no enviados, pero para una demostración suponemos que la respuesta pequeña cabe en el búfer de envío.
char buf[4096];
ssize_t r = recv(fd, buf, sizeof buf, 0);
if (r > 0) {
send(fd, buf, r, 0);
}Detección de desconexiones
Un valor devuelto de recv() igual a 0 significa que el cliente realizó un cierre ordenado. Un valor negativo con cualquier valor distinto de EAGAIN indica un error real.
En ambos casos, elimine el descriptor de epoll y ciérrelo con close() para liberar recursos y detener futuros eventos.
if (r == 0 || (r < 0 && errno != EAGAIN)) {
epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL);
close(fd);
}El bucle completo
Combine las piezas: espere los eventos, determine si el descriptor corresponde al socket de escucha o a un cliente y actúe en consecuencia.
Este bucle compacto es un servidor de eco concurrente completamente funcional. Un subproceso, muchos clientes y ningún subproceso por conexión.
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);
}
}Pruebas y próximos pasos
Compile en Linux y conéctese con nc localhost 8080; todo lo que escriba volverá a aparecer. Abra varios terminales para comprobar la concurrencia.
Para hacerlo más robusto: almacene en búfer los envíos parciales, gestione EPOLLOUT, cambie a EPOLLET con un vaciado completo y gestione EPOLLRDHUP para los cierres parciales.
Comprobación rápida
Compruebe cuánto ha entendido del funcionamiento del servidor de eco.
Repaso
Ha creado un servidor de eco con epoll: crear, establecer SO_REUSEADDR, asociar, escuchar y pasar a modo no bloqueante. Registre el socket de escucha, acepte clientes en un bucle y devuelva los datos con recv()/send().
Trate un valor de retorno 0 como una desconexión y cierre la conexión correctamente. A partir de este esqueleto puede desarrollar un servidor de red de alto rendimiento y de un solo hilo.
Aprende C con un tutor de IA — gratis
Escribe y ejecuta código real en tu navegador, obtén ayuda instantánea de un tutor de IA disponible 24/7 y continúa donde lo dejaste en la web o en la aplicación.
- Cursos
- 39
- Lecciones
- 144
Preguntas frecuentes
¿La lección «Un servidor de eco sencillo» es gratis?
Sí — el texto completo de «Un servidor de eco sencillo» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de C Academy, actualiza a CoddyKit PRO. El curso de C Academy incluye 4 lecciones en total.
¿Qué aprenderé en «Un servidor de eco sencillo»?
Atienda a muchos clientes a la vez Practicas C Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.
¿Necesito experiencia previa para empezar C Academy?
No se requiere experiencia previa. C Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 4 de 4.
¿Cuánto tiempo toma la lección «Un servidor de eco sencillo»?
La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.
¿Puedo escribir y ejecutar código en esta lección de C Academy?
Sí. Cada lección de C Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.
Todas las lecciones de este curso
- E/S bloqueante frente a no bloqueante
- Configurar epoll
- El bucle de eventos
- Un servidor de eco sencillo