Socket to ’em

The really cool, game-changing thing about the Internet is that it allows us to leverage the true N^2 value of large networks. Specifically, whenever a computer has a persistent Internet connection, it can exchange information with any other Internet-connected device at any time, quickly and easily.

When writing Internet-aware applications, such communications are often done with TCP or UDP sockets. These virtual connections represent a specific connection from one computer to another, through which data can be transferred.

What is needed for TCP/IP (UDP is similar but without verification steps) is a server program (to listen for incoming connections) and a client program (to contact a server with a request). As an easily-modified example, here is a server program in C that accepts a single byte, increments it (allowing rollover), and sends it back.

/* server.c : minimal TCP server that receives one uint8,
              applies myFunction() (here: ++ with wrap-around),
              and sends it back.                                */

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>

#define PORT 10000          /* listen port; change if you like */

/* Your pluggable transform ---------------------------------- */
static uint8_t myFunction(uint8_t x) {
    return x + 1;           /* uint8_t overflow wraps naturally */
}
/* ----------------------------------------------------------- */

int main(void){

    int srv_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (srv_fd < 0) { perror("socket"); exit(EXIT_FAILURE); }

    /* allow quick restart (otherwise TIME_WAIT delays) */
    int opt = 1;
    setsockopt(srv_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof opt);

    struct sockaddr_in addr = {0};
    addr.sin_family      = AF_INET;
    addr.sin_addr.s_addr = htonl(INADDR_ANY); /* 0.0.0.0 */
    addr.sin_port        = htons(PORT);

    if (bind(srv_fd, (struct sockaddr *)&addr, sizeof addr) < 0) {
        perror("bind"); exit(EXIT_FAILURE);
    }
    if (listen(srv_fd, 1) < 0) { perror("listen"); exit(EXIT_FAILURE); }

    printf("Server listening on port %d …\n", PORT);

    for (;;) {
        struct sockaddr_in cli_addr;
        socklen_t cli_len = sizeof cli_addr;
        int cfd = accept(srv_fd, (struct sockaddr *)&cli_addr, &cli_len);
        if (cfd < 0) { perror("accept"); continue; }

        uint8_t in_byte;
        ssize_t n = recv(cfd, &in_byte, 1, 0);
        if (n == 1) {
            uint8_t out_byte = myFunction(in_byte);
            send(cfd, &out_byte, 1, 0);
            printf(" %u -> %u from %s\n",
                   in_byte, out_byte, inet_ntoa(cli_addr.sin_addr));
        }
        close(cfd);
    }
}

Here is a client program, which calls the server, sends a byte, and reports what it gets back.
(Change the IP address if the programs are not running on the same machine.)

/* client.c : minimal TCP client that sends a uint8
              and prints the transformed result.               */

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>

#define PORT 10000          /* must match server */
#define SERVER_IP "127.0.0.1" /* change to LAN IP if needed */

int main(int argc, char **argv){

    uint8_t value = 42;                          /* default test value */
    if (argc == 2) value = (uint8_t)atoi(argv[1]);

    int fd = socket(AF_INET, SOCK_STREAM, 0);
    if (fd < 0) { perror("socket"); exit(EXIT_FAILURE); }

    struct sockaddr_in srv = {0};
    srv.sin_family = AF_INET;
    srv.sin_port   = htons(PORT);
    if (inet_pton(AF_INET, SERVER_IP, &srv.sin_addr) != 1) {
        fprintf(stderr, "Bad server IP\n"); exit(EXIT_FAILURE);
    }

    if (connect(fd, (struct sockaddr *)&srv, sizeof srv) < 0) {
        perror("connect"); exit(EXIT_FAILURE);
    }

    if (send(fd, &value, 1, 0) != 1) { perror("send"); exit(EXIT_FAILURE); }

    uint8_t reply;
    if (recv(fd, &reply, 1, 0) != 1) { perror("recv"); exit(EXIT_FAILURE); }

    printf("Sent %u, got %u\n", value, reply);

    close(fd);
    return 0;
}

(Code provided by GPT-o3.)

This entry was posted in C, Coding, Digital, Digital Citizenship, HOW-TO, Internet, Linux, Networking, System Administration. Bookmark the permalink.

Leave a Reply