Handling Multiple Clients
select and poll.
Handling Multiple Clients is a free C Academy lesson on CoddyKit — lesson 4 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the C Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
The Concurrency Problem
A simple server handles one client at a time. If a client is slow, everyone else waits. To serve many clients concurrently, you need a different model.
Approaches to Concurrency
Three common strategies:
- Thread/process per client: simple but heavy at scale
- I/O multiplexing with
selectorpoll: one thread watches many sockets - Event loops with
epoll/kqueue: scales to thousands
What select Does
select() watches a set of file descriptors and tells you which are ready for reading, writing, or have errors, all in a single blocking call. This lets one thread serve many sockets.
fd_set Basics
select uses an fd_set bitmask. Manage it with macros: FD_ZERO, FD_SET, FD_CLR, and 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 */
}Calling select
select needs the highest fd plus one, and modifies the set in place to mark ready descriptors. Because it is destructive, you rebuild the set before each call.
#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 */
}The select Server Loop
The pattern: rebuild the set, call select, then for each ready fd either accept a new client (if it is the listener) or read data (if it is a client).
#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 */
}
}
}Tracking Clients
When you accept a new connection, add its fd to the master set and update maxfd. When a client disconnects (recv returns 0), close it and FD_CLR it from the set.
#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);
}Limits of select
select has drawbacks:
- Capped at
FD_SETUPdescriptors (often 1024) - O(n) scan of all fds every call
- Set rebuilt each iteration
For many connections, poll or epoll scale better.
What poll Offers
poll() takes an array of struct pollfd instead of a fixed bitmask, so it has no 1024-descriptor limit and does not destroy the input on each call.
#include <poll.h>
void setup_poll(struct pollfd *pfd, int listen_fd) {
pfd[0].fd = listen_fd;
pfd[0].events = POLLIN; /* notify when readable */
}Calling poll
poll blocks until at least one fd is ready (or the timeout fires), then sets revents on each ready entry.
#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;
}Scaling Up: epoll
For thousands of connections, Linux's epoll (and BSD's kqueue) deliver only the ready descriptors in O(1) per event, avoiding the full scan that select and poll perform.
Quick Check
Test your understanding of handling multiple clients.
Recap
You learned to serve many clients with one thread.
selectwatches many fds; manage with FD_ macros- Rebuild the set each loop because select is destructive
- Add accepted clients to the set; drop on disconnect
pollavoids the 1024 limit;epollscales to thousands
Frequently asked questions
Is the “Handling Multiple Clients” lesson free?
Yes — the full text of “Handling Multiple Clients” is free to read here on the web, and the C Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the C Academy course, upgrade to CoddyKit PRO.
What will I learn in “Handling Multiple Clients”?
select and poll. You practise C Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start C Academy?
No prior experience is required. C Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 4 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “Handling Multiple Clients” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this C Academy lesson?
Yes. Every C Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- Sockets Overview
- TCP Server
- TCP Client
- Handling Multiple Clients