Networking in C · intermediate · ~15 min

A complete simple TCP server (localhost)

Read and run a complete TCP server. It binds to 127.0.0.1, accepts one client, and echoes a single line back.

Lesson

The full server, end to end

This lesson puts every piece together in order:

socket → setsockopt → bind → listen → accept → read/write → close

Each call has one job:

  • socket creates the listening endpoint.
  • setsockopt sets an option on it (here, address reuse).
  • bind attaches the socket to an address and port.
  • listen marks it ready to accept incoming connections.
  • accept waits for a client and returns a new socket for that client.
  • read/write (here recv/send) move data over the connection.
  • close releases each socket.

The server handles one connection, then exits. That keeps it small and predictable, which makes it ideal for labs and experiments.

Code examples

#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>

int main(void) {
    int srv = socket(AF_INET, SOCK_STREAM, 0);
    int yes = 1; setsockopt(srv, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes);

    struct sockaddr_in a; memset(&a, 0, sizeof a);
    a.sin_family = AF_INET;
    a.sin_port   = htons(8080);
    a.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
    if (bind(srv, (struct sockaddr *)&a, sizeof a) < 0) { perror("bind"); return 1; }
    if (listen(srv, 16) < 0) { perror("listen"); return 1; }

    int client = accept(srv, NULL, NULL);
    if (client < 0) { perror("accept"); return 1; }

    char buf[256];
    ssize_t n = recv(client, buf, sizeof buf - 1, 0);
    if (n > 0) {
        buf[n] = 0;
        printf("server: got %s", buf);
        send(client, buf, (size_t)n, 0);     /* echo */
    }
    close(client);
    close(srv);
    return 0;
}

Common mistakes

Common mistakes

  • Forgetting SO_REUSEADDR. Without it, your second run can fail with EADDRINUSE because the port is still held from the previous run.
  • Binding to INADDR_ANY for a localhost lab. INADDR_ANY accepts traffic from any network interface. For a same-machine lab, use INADDR_LOOPBACK so only local (127.0.0.1) traffic can reach you.

Summary

Key takeaways

  • The full server lifecycle is: socket → setsockopt → bind → listen → accept → recv/send → close.
  • You call close twice: once for the client socket, once for the listening socket.
  • For labs, use INADDR_LOOPBACK (local only) and SO_REUSEADDR (clean restarts).

Practice with these exercises