typestar

tcp_echo.c in C

A single-threaded echo server: bind, listen, accept, echo, repeat.

#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>

#define PORT 9099
#define BACKLOG 4

static int serve_client(int client) {
    char buffer[512];
    ssize_t n;

    while ((n = read(client, buffer, sizeof buffer)) > 0) {
        ssize_t written = 0;
        while (written < n) {
            ssize_t w = write(client, buffer + written, (size_t) (n - written));
            if (w <= 0) {
                return 0;
            }
            written += w;
        }
    }
    return n == 0;
}

int main(void) {
    int listener = socket(AF_INET, SOCK_STREAM, 0);
    if (listener < 0) {
        perror("socket");
        return 1;
    }

    int reuse = 1;
    setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof reuse);

    struct sockaddr_in addr;
    memset(&addr, 0, sizeof addr);
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
    addr.sin_port = htons(PORT);

    if (bind(listener, (struct sockaddr *) &addr, sizeof addr) != 0) {
        perror("bind");
        close(listener);
        return 1;
    }
    if (listen(listener, BACKLOG) != 0) {
        perror("listen");
        close(listener);
        return 1;
    }

    printf("echoing on 127.0.0.1:%d\n", PORT);

    for (int served = 0; served < 3; served++) {
        struct sockaddr_in peer;
        socklen_t peer_len = sizeof peer;
        int client = accept(listener, (struct sockaddr *) &peer, &peer_len);
        if (client < 0) {
            perror("accept");
            continue;
        }

        char who[INET_ADDRSTRLEN] = "?";
        inet_ntop(AF_INET, &peer.sin_addr, who, sizeof who);
        printf("client from %s\n", who);

        if (!serve_client(client)) {
            fprintf(stderr, "client dropped\n");
        }
        close(client);
    }

    close(listener);
    return 0;
}

How it works

  1. SO_REUSEADDR lets the port be rebound immediately after a restart.
  2. The accept loop handles one client at a time to completion.
  3. Every error path closes what it opened and reports why.

Keywords and builtins used here

The run, in numbers

Lines
77
Characters to type
1502
Tokens
420
Three-star pace
110 tpm

At the three-star pace of 110 tokens a minute, this run takes about 229 seconds.

Type this snippet

Step 1 of 1 in Encore, step 14 of 14 in Systems programming.

← Previous