C Academy · Aula

Um servidor de eco simples

Atenda a vários clientes simultaneamente.

Aula 4 de 413 etapas

Um servidor de eco simples é uma aula grátis de C Academy no CoddyKit. Esta é a aula 4 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de C Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de C Academy inclui 4 aulas no total.

O que estamos construindo

Um servidor de eco aceita conexões TCP e envia de volta quaisquer bytes enviados por um cliente. Ele é o "olá, mundo" da programação de redes.

Nós o construiremos sobre epoll para que uma única thread atenda muitos clientes ao mesmo tempo. As partes são: um soquete de escuta, o loop de epoll e o processamento de leitura e depois escrita de cada cliente.

Criando o soquete de escuta

Comece com socket() para um ponto de extremidade TCP IPv4. A combinação é AF_INET, SOCK_STREAM e o protocolo 0.

Isso retorna um descritor de arquivo que associaremos a um endereço, marcaremos como não bloqueante e, por fim, registraremos no epoll. Verifique se o retorno é -1 em toda chamada de sistema.

int listen_fd = socket(AF_INET, SOCK_STREAM, 0);
if (listen_fd == -1) { perror("socket"); exit(1); }

Reutilizando o endereço

Antes de associar o endereço, defina SO_REUSEADDR com setsockopt(). Isso permite que o servidor seja reiniciado e associado novamente à mesma porta sem esperar o término do estado TIME_WAIT.

Sem essa opção, uma reinicialização rápida frequentemente falha com EADDRINUSE, uma surpresa frustrante durante o desenvolvimento.

int yes = 1;
setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes);

Associando a uma porta

Preencha uma struct sockaddr_in com a família, a porta e o endereço. Use htons() para a porta e INADDR_ANY para escutar em todas as interfaces.

Em seguida, chame bind() para associar o soquete a esse endereço. htons converte a ordem de bytes do host para a ordem de bytes da rede, o que é obrigatório.

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);

Escutando e passando ao modo não bloqueante

Chame listen() para marcar o soquete como passivo e definir uma fila para conexões pendentes. SOMAXCONN solicita o máximo permitido pelo sistema.

Depois, passe o soquete para o modo não bloqueante para que accept() nunca interrompa o loop de eventos. Agora ele está pronto para ser registrado no epoll.

listen(listen_fd, SOMAXCONN);
set_nonblocking(listen_fd);

Registrando o soquete de escuta

Crie a instância de epoll e adicione o soquete de escuta com EPOLLIN. Um evento de leitura aqui significa que um novo cliente está aguardando para ser aceito.

Armazenamos o fd em data.fd para podermos reconhecer o soquete de escuta dentro do loop.

int epfd = epoll_create1(0);
struct epoll_event ev = { .events = EPOLLIN, .data.fd = listen_fd };
epoll_ctl(epfd, EPOLL_CTL_ADD, listen_fd, &ev);

Aceitando um cliente

Quando o soquete de escuta estiver pronto para leitura, repita accept() até receber EAGAIN. Cada novo soquete de cliente é configurado como não bloqueante e registrado para EPOLLIN.

A partir desse momento, epoll nos informará sempre que esse cliente enviar dados que possamos 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);
}

A lógica do eco

Para um cliente pronto, use recv() para ler em um buffer. Se receber bytes, envie os mesmos bytes de volta diretamente com send().

Essa leitura seguida de escrita simples é o eco. Em produção, você armazenaria em buffer os bytes não enviados, mas, para uma demonstração, presumimos que a pequena resposta caiba no buffer de envio.

char buf[4096];
ssize_t r = recv(fd, buf, sizeof buf, 0);
if (r > 0) {
    send(fd, buf, r, 0);
}

Detectando a desconexão

Um retorno de recv() igual a 0 significa que o cliente realizou um desligamento ordenado. Um retorno negativo com qualquer valor diferente de EAGAIN é um erro real.

Nos dois casos, remova o descritor do epoll e use close() para fechá-lo, liberando recursos e interrompendo novos eventos.

if (r == 0 || (r < 0 && errno != EAGAIN)) {
    epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL);
    close(fd);
}

O loop completo

Combine as partes: aguarde eventos, verifique se o descritor é o soquete de escuta ou um cliente e aja de acordo.

Esse loop compacto é um servidor de eco simultâneo totalmente funcional. Uma thread, muitos clientes, nenhuma thread por conexão.

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);
    }
}

Testes e próximos passos

Compile no Linux e conecte-se com nc localhost 8080; tudo o que você digitar voltará. Abra vários terminais para comprovar a simultaneidade.

Para torná-lo mais robusto: armazene em buffer os envios parciais, processe EPOLLOUT, mude para EPOLLET esvaziando completamente os dados e processe EPOLLRDHUP para meios-desligamentos.

Verificação rápida

Teste sua compreensão do fluxo do servidor de eco.

Recapitulação

Você construiu um servidor de eco com epoll: criar, definir SO_REUSEADDR, associar, escutar e ativar o modo não bloqueante. Registre o servidor de escuta, aceite clientes em um laço e faça o eco com recv()/send().

Trate um retorno 0 como uma desconexão e feche tudo corretamente. A partir desse esqueleto, você pode desenvolver um servidor de rede de alto desempenho e thread único.

Grátis para começar

Aprenda C com um tutor de IA — grátis

Escreva e execute código real no seu navegador, obtenha ajuda instantânea de um tutor de IA 24/7 e continue de onde parou na web ou no app.

Cursos
39
Aulas
144

Perguntas Frequentes

A aula “Um servidor de eco simples” é grátis?

Sim — o texto completo de “Um servidor de eco simples” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de C Academy, atualize para CoddyKit PRO. O curso de C Academy inclui 4 aulas no total.

O que vou aprender em “Um servidor de eco simples”?

Atenda a vários clientes simultaneamente. Você pratica C Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.

Preciso ter experiência prévia para começar C Academy?

Nenhuma experiência prévia é necessária. C Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 4 de 4.

Quanto tempo leva a aula “Um servidor de eco simples”?

A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.

Posso escrever e executar código nesta aula de C Academy?

Sim. Cada aula de C Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.

Todas as aulas deste curso

  1. E/S bloqueante versus não bloqueante
  2. Configurando epoll
  3. O laço de eventos
  4. Um servidor de eco simples
← Voltar para C Academy