Networking in C · intermediate · ~10 min

listen() and accept() — the server side

Move a socket from the bound state into the listening state, then accept incoming client connections.

Lesson

Two steps to start serving

A server socket becomes usable in two steps: first you tell the kernel to start listening, then you accept connections one at a time.

listen() — start accepting connections

listen(fd, backlog);
  • fd is the bound socket. listen() marks it as ready to accept connections.
  • backlog sets the kernel's queue depth: how many half-finished handshakes (pending SYN/ACK exchanges) the kernel will hold while you are busy.

For labs, a backlog of 32 is fine.

accept() — take one connection

accept(fd, &peer, &peer_len);
  • accept() blocks until a client connects. (Blocking means the call waits and does not return until something happens.)
  • It then returns a new file descriptor for that single connection.
  • The original fd keeps listening for the next client.

So you end up with two sockets: the listening socket and a per-client socket.

Server loop skeleton

listen(srv_fd, 32);
for (;;) {
    struct sockaddr_in peer; socklen_t plen = sizeof peer;
    int client_fd = accept(srv_fd, (struct sockaddr *)&peer, &plen);
    if (client_fd < 0) { perror("accept"); continue; }
    /* talk to client_fd, then close it */
    close(client_fd);
}

The loop accepts one client, handles it, closes its socket, and goes back to wait for the next one.

Code examples

int srv = socket(AF_INET, SOCK_STREAM, 0);
/* … setsockopt + bind on 127.0.0.1:8080 … */
listen(srv, 32);

struct sockaddr_in peer; socklen_t plen = sizeof peer;
int client = accept(srv, (struct sockaddr *)&peer, &plen);
write(client, "hi\n", 3);
close(client);
close(srv);

Common mistakes

  • Forgetting to close client_fd after each connection. Each open descriptor that is never closed is a file-descriptor leak; over time the process runs out of descriptors.
  • Treating srv_fd and client_fd as the same thing. They are two separate sockets. The server socket listens; the client socket talks to one connected peer.

Summary

  • listen() puts a bound socket into listening mode.
  • accept() blocks until a client connects, then returns a fresh file descriptor for that connection.
  • The listening socket stays open and keeps accepting more clients.
  • Close the per-client descriptor when you are done with it.

Practice with these exercises