Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Fundamentals of Network Programming with Socket API

Tech May 15 1

Core Networking Concepts

1.1 Local and Wide Area Networks

A local area network (LAN) connects computers and devices within a limited geographic area, forming a private communication network. In contrast, a wide area network (WAN), also known as the public internet, links multiple LANs or metropolitan networks across regions.

1.2 IP Addressing

An IP address is essentially an integer identifying a device on a network. Two versions exist: IPv4 and IPv6.

  • IPv4

    • Uses a 32-bit integer (4 bytes), represented as four 8-bit segments.
    • Commonly expressed in dotted-decimal notation: 192.168.10.27.
    • Each segment ranges from 0 to 255, yielding a total of $2^{32}$ unique addresses.
  • IPv6

    • Employs a 128-bit integer (16 bytes), allowing for $2^{128}$ possible addresses.
    • Written in hexadecimal format: 2001:0db8:3c4d:0015:0000:0000:1a2b.
    • Divided into eight 16-bit segments.

1.3 Port Numbers

Ports are numeric identifiers used to direct network traffic to specific processes on a host. They are unsigned 16-bit integers ranging from 0 to 65535. A process must bind to a port to receive network data; multiple processes cannot share the same port.

1.4 OSI Model

The Open Systtems Interconnection (OSI) model is a conceptual framework developed by ISO in 1985 to standardize network communication layers.

Network Protocols

TCP, UDP, IP, and Ethernet form the foundation of modern networking.

Socket Programming Interface

Sockets provide a standardized API for network communication between client and server applications. Key componnets include IP address, port number, and data payload.

3.1 Byte Order

Data representation in memory varies between systems:

  • Little-endian (host byte order): Lower-order bytes stored at lower memory addresses (common on x86).
  • Big-endian (network byte order): Lower-order bytes stored at higher memory addresses. All socket operations use big-endian format.

For example, the value 0x12345678 is transmitted as 12 34 56 78 over the network.

3.2 Endianness Conversion Functions

#include <arpa/inet.h>

uint16_t htons(uint16_t hostshort);
uint32_t htonl(uint32_t hostlong);

uint16_t ntohs(uint16_t netshort);
uint32_t ntohl(uint32_t netlong);

These functions convert between host and network byte orders.

3.3 IP Address Translation

Convert string representations to binary format:

int inet_pton(int af, const char *src, void *dst);
  • af: Adress family (AF_INET or AF_INET6).
  • src: Input string like 192.168.10.27.
  • dst: Output buffer for the converted 32-bit or 128-bit integer.

Convert binary back to string:

const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);

Legacy functions for IPv4 only:

in_addr_t inet_addr(const char *cp);
char *inet_ntoa(struct in_addr in);

TCP Communication Flow

TCP is connection-oriented, reliable, and stream-based.

4.1 Server Workflow

int lfd = socket(...);       // Create listening socket
bind(lfd, ...);              // Bind to IP and port
listen(lfd, backlog);        // Start listening
int cfd = accept(lfd, ...);   // Accept incoming connection
read(cfd, buf, size);         // Receive data
write(cfd, buf, size);        // Send data
close(cfd);                   // Close connection

4.2 Client Workflow

int cfd = socket(...);        // Create socket
connect(cfd, ...);            // Connect to server
recv(cfd, buf, size, 0);      // Receive data
send(cfd, buf, size, 0);      // Send data
close(cfd);                   // Close connection

4.3 Socket Function

int socket(int domain, int type, int protocol);
  • domain: Protocol family (AF_INET, AF_UNIX, etc.).
  • type: Socket type (SOCK_STREAM for TCP, SOCK_DGRAM for UDP).
  • protocol: Usually 0 to use default protocol.

4.4 Binding Addresses

struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(8080);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
bind(sockfd, (struct sockaddr*)&addr, sizeof(addr));

4.5 Listening Queue

int listen(int sockfd, int backlog);

Maximum pending connections in queue (typically up to 128).

4.6 Accepting Connections

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

Returns a new file descriptor representing the established connection. The original sockfd remains open for listening.

4.7 Connecting Clients

int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

Initiates TCP handshake. For UDP, only records server address without sending packets.

4.8 Data Transfer

Use recv() and send() for reliable communication:

ssize_t recv(int sockfd, void *buf, size_t len, int flags);
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
  • Returns number of bytes transferred, 0 on peer close, -1 on error.

4.9 File Descriptor Roles

  • Server uses one listening FD and one per active connection.
  • Client uses one FD for all communication.

Example Server Implementation

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

int main() {
    int server_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (server_fd < 0) {
        perror("Socket creation failed");
        exit(-1);
    }

    struct sockaddr_in server_addr;
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(8080);
    inet_pton(AF_INET, "192.168.23.139", &server_addr.sin_addr);

    if (bind(server_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
        perror("Bind failed");
        close(server_fd);
        exit(-1);
    }

    if (listen(server_fd, 128) < 0) {
        perror("Listen failed");
        close(server_fd);
        exit(-1);
    }

    struct sockaddr_in client_addr;
    socklen_t client_len = sizeof(client_addr);
    int client_fd = accept(server_fd, (struct sockaddr*)&client_addr, &client_len);

    char ip_str[32];
    printf("Client connected: %s:%d\n",
           inet_ntop(AF_INET, &client_addr.sin_addr, ip_str, sizeof(ip_str)),
           ntohs(client_addr.sin_port));

    while (1) {
        char buffer[1024];
        ssize_t n = recv(client_fd, buffer, sizeof(buffer), 0);
        if (n > 0) {
            printf("Received: %s\n", buffer);
            send(client_fd, buffer, n, 0);
        } else if (n == 0) {
            break;
        } else {
            perror("Receive error");
            break;
        }
    }

    close(client_fd);
    close(server_fd);
    return 0;
}

Example Client Implementation

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

int main() {
    int client_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (client_fd < 0) {
        perror("Socket creation failed");
        exit(-1);
    }

    struct sockaddr_in server_addr;
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(8080);
    inet_pton(AF_INET, "192.168.23.139", &server_addr.sin_addr);

    if (connect(client_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
        perror("Connection failed");
        close(client_fd);
        exit(-1);
    }

    char ip_str[32];
    printf("Connected to server: %s:%d\n",
           inet_ntop(AF_INET, &server_addr.sin_addr, ip_str, sizeof(ip_str)),
           ntohs(server_addr.sin_port));

    int count = 0;
    while (1) {
        char message[1024];
        snprintf(message, sizeof(message), "Hello World %d\n", count++);
        send(client_fd, message, strlen(message), 0);

        char response[1024];
        ssize_t n = recv(client_fd, response, sizeof(response), 0);
        if (n > 0) {
            printf("Server: %s\n", response);
        } else if (n == 0) {
            break;
        } else {
            perror("Receive error");
            break;
        }
        sleep(1);
    }

    close(client_fd);
    return 0;
}

Concurrent Server Using Threads

#include <pthread.h>

void* handle_client(void* arg) {
    struct addrInfo* info = (struct addrInfo*)arg;
    char ip[32];
    printf("Client: %s:%d\n",
           inet_ntop(AF_INET, &info->addr.sin_addr, ip, sizeof(ip)),
           ntohs(info->addr.sin_port));

    char buffer[1024];
    while ((recv(info->cfd, buffer, sizeof(buffer), 0)) > 0) {
        printf("Client %d: %s\n", info->number, buffer);
        send(info->cfd, buffer, strlen(buffer), 0);
    }

    close(info->cfd);
    free(arg);
    return NULL;
}

// Main loop creates thread for each incoming connection

TCP Handshake and Termination

Three-Way Handshake

  1. SYN: Client sends SYN=1, seq=J.
  2. SYN+ACK: Server responds with SYN=1, ACK=1, ack=J+1, seq=K.
  3. ACK: Client confirms with ACK=1, ack=K+1.

Four-Way Termination

  1. FIN: Client sends FIN=1.
  2. ACK: Server replies with ACK=1, ack=seq+1.
  3. FIN: Server sends its own FIN=1.
  4. ACK: Client acknowledges, waits 2MSL before closing.

Thread Pool Design

A thread pool manages a fixed number of worker threads to handle tasks efficiently:

  • Task Queue: Stores pending work items (producer-consumer pattern).
  • Worker Threads: Continuously poll the queue for jobs.
  • Manager Thread: Adjusts pool size based on load.

Benefits:

  • Reduces overhead of frequent thread creation/destruction.
  • Enables immediate task execution.
  • Prevents system overload during high concurrency.

Common use cases: web servers, real-time systems, bursty request handling.

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.