0Pricing
C Academy · Aula

Lidando com vários clientes

select e poll.

Lidando com vários clientes é 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 problema da concorrência

Um servidor simples atende um cliente por vez. Se um cliente for lento, todos os outros terão de esperar. Para atender muitos clientes simultaneamente, você precisa de um modelo diferente.

Abordagens para concorrência

Três estratégias comuns:

  • Uma thread ou um processo por cliente: simples, mas pesado em grande escala
  • Multiplexação de E/S com select ou poll: uma thread monitora muitos sockets
  • Loops de eventos com epoll/kqueue: suporta milhares de conexões

O que select faz

select() monitora um conjunto de descritores de arquivos e informa quais estão prontos para leitura ou escrita, ou apresentam erros, tudo em uma única chamada bloqueante. Isso permite que uma thread atenda muitos sockets.

Noções básicas de fd_set

select usa uma máscara de bits fd_set. Gerencie-a com as macros: FD_ZERO, FD_SET, FD_CLR e FD_ISSET.

#include <sys/select.h>

void setup_set(fd_set *set, int listen_fd) {
    FD_ZERO(set);          /* clear all */
    FD_SET(listen_fd, set); /* watch the listener */
}

Chamando select

select precisa do maior fd mais um e modifica o conjunto no próprio local para marcar os descritores prontos. Como ele é destrutivo, você precisa reconstruir o conjunto antes de cada chamada.

#include <sys/select.h>
#include <stdio.h>

int wait_ready(int maxfd, fd_set *read_set) {
    int n = select(maxfd + 1, read_set, NULL, NULL, NULL);
    if (n < 0) perror("select");
    return n; /* number of ready fds */
}

O loop de servidor com select

O padrão é: reconstrua o conjunto, chame select e, em seguida, para cada fd pronto, aceite um novo cliente se ele for o escutador ou leia dados se for um cliente.

#include <sys/select.h>

void loop_skeleton(int listen_fd, fd_set *master, int maxfd) {
    fd_set work;
    for (;;) {
        work = *master;           /* copy, select destroys it */
        select(maxfd + 1, &work, NULL, NULL, NULL);
        for (int fd = 0; fd <= maxfd; fd++) {
            if (!FD_ISSET(fd, &work)) continue;
            /* fd == listen_fd -> accept; else -> recv */
        }
    }
}

Acompanhando os clientes

Ao aceitar uma nova conexão, adicione o fd dela ao conjunto principal e atualize maxfd. Quando um cliente se desconectar (recv retornar 0), use close e remova-o do conjunto com FD_CLR.

#include <sys/select.h>
#include <unistd.h>

void add_client(fd_set *master, int *maxfd, int conn) {
    FD_SET(conn, master);
    if (conn > *maxfd) *maxfd = conn;
}
void drop_client(fd_set *master, int conn) {
    close(conn);
    FD_CLR(conn, master);
}

Limitações de select

select tem algumas desvantagens:

  • Limitado a FD_SETUP descritores (geralmente 1024)
  • Varredura O(n) de todos os fds a cada chamada
  • O conjunto precisa ser reconstruído a cada iteração

Para muitas conexões, poll ou epoll oferecem melhor escalabilidade.

O que poll oferece

poll() recebe uma matriz de struct pollfd em vez de uma máscara de bits fixa. Assim, não tem o limite de 1024 descritores e não destrói a entrada a cada chamada.

#include <poll.h>

void setup_poll(struct pollfd *pfd, int listen_fd) {
    pfd[0].fd = listen_fd;
    pfd[0].events = POLLIN; /* notify when readable */
}

Chamando poll

poll bloqueia até que pelo menos um fd esteja pronto (ou até que o tempo limite expire) e, em seguida, define revents em cada entrada pronta.

#include <poll.h>
#include <stdio.h>

int poll_ready(struct pollfd *pfds, int count) {
    int n = poll(pfds, count, -1); /* -1 = block forever */
    if (n < 0) perror("poll");
    return n;
}

Expandindo a escala: epoll

Para milhares de conexões, o epoll do Linux (e o kqueue do BSD) fornece apenas os descritores prontos, em O(1) por evento, evitando a varredura completa realizada por select e poll.

Verificação rápida

Teste sua compreensão sobre como lidar com vários clientes.

Recapitulação

Você aprendeu a atender muitos clientes com uma única thread.

  • select monitora muitos fds; gerencie-os com macros FD_
  • Reconstrua o conjunto a cada loop, pois select é destrutivo
  • Adicione os clientes aceitos ao conjunto; remova-os ao se desconectarem
  • poll evita o limite de 1024; epoll escala para milhares

Perguntas Frequentes

A aula “Lidando com vários clientes” é grátis?

Sim — o texto completo de “Lidando com vários clientes” é 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 “Lidando com vários clientes”?

select e poll. 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 “Lidando com vários clientes”?

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. Visão geral dos sockets
  2. Servidor TCP
  3. Cliente TCP
  4. Lidando com vários clientes
← Voltar para C Academy