Build your own Redis
The Guide below is a sequence of tasks which will be divided into various levels and ultimately will help you build your own REDIS
The provided code is a basic TCP server implemented in C.
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
int main() {
    // Disable output buffering
    setbuf(stdout, NULL);
    setbuf(stderr, NULL);
    // Debugging message
    printf("Logs from your program will appear here!\n");
    int server_fd, client_addr_len;
    struct sockaddr_in client_addr;
    // Step 1: Create a socket
    server_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (server_fd == -1) {
        printf("Socket creation failed: %s...\n", strerror(errno));
        return 1;
    }
    // Step 2: Set socket options
    int reuse = 1;
    if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0) {
        printf("SO_REUSEADDR failed: %s \n", strerror(errno));
        return 1;
    }
    // Step 3: Define server address
    struct sockaddr_in serv_addr = {
        .sin_family = AF_INET,
        .sin_port = htons(6379),
        .sin_addr = { htonl(INADDR_ANY) },
    };
    // Step 4: Bind the socket
    if (bind(server_fd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) != 0) {
        printf("Bind failed: %s \n", strerror(errno));
        return 1;
    }
    // Step 5: Listen for connections
    int connection_backlog = 5;
    if (listen(server_fd, connection_backlog) != 0) {
        printf("Listen failed: %s \n", strerror(errno));
        return 1;
    }
    // Step 6: Accept a client connection
    printf("Waiting for a client to connect...\n");
    client_addr_len = sizeof(client_addr);
    accept(server_fd, (struct sockaddr *) &client_addr, &client_addr_len);
    printf("Client connected\n");
    // Step 7: Close the server socket
    close(server_fd);
    return 0;
}Let's break down each part to understand its functionality, especially for someone new to socket programming.
Header files
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>#include <stdio.h>: Provides functions for input and output operations, such asprintffor displaying text.#include <stdlib.h>: Offers general utilities, including memory allocation (malloc,free) and process control (exit).#include <sys/socket.h>: Contains definitions for socket functions and structures, likesocket,bind, andaccept.#include <netinet/in.h>: Defines structures for internet operations, such assockaddr_in, which is used for handling IP addresses.#include <netinet/ip.h>: Provides declarations for the IP header structure.#include <string.h>: Offers functions for manipulating C strings and memory, likememsetandstrerror.#include <errno.h>: Defines macros for reporting and retrieving error conditions through theerrnovariable.#include <unistd.h>: Declares standard symbolic constants and types, and declares miscellaneous functions, such asclosefor closing file descriptors.
2. Main Function:
int main() {
    // Disable output buffering
    setbuf(stdout, NULL);
    setbuf(stderr, NULL);int main() {: The entry point of the program.setbuf(stdout, NULL);andsetbuf(stderr, NULL);: These functions disable buffering for standard output (stdout) and standard error (stderr). This means that any output to the console is displayed immediately, which is helpful for debugging purposes.
3. Debugging Message:
printf("Logs from your program will appear here!\n");printf: Outputs the specified string to the console. This line informs the user that the program has started and is ready to log messages.
4. Variable Declarations:
int server_fd, client_addr_len;
    struct sockaddr_in client_addr;int server_fd, client_addr_len;: Declares two integer variables.server_fdwill store the file descriptor for the server socket, andclient_addr_lenwill hold the size of the client's address structure.struct sockaddr_in client_addr;: Declares a structure to store the client's address information.sockaddr_inis specifically designed for handling internet addresses.
5. Socket Creation:
server_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (server_fd == -1) {
        printf("Socket creation failed: %s...\n", strerror(errno));
        return 1;
    }server_fd = socket(AF_INET, SOCK_STREAM, 0);: Creates a new socket.AF_INET: Specifies the address family for IPv4.SOCK_STREAM: Indicates that the socket type is stream-oriented, which is used for TCP connections.0: Specifies the protocol. Setting it to0lets the system choose the appropriate protocol based on the socket type and address family.
if (server_fd == -1) { ... }: Checks if the socket creation failed. Ifsocketreturns-1, an error occurred.strerror(errno): Converts the error number (errno) into a human-readable string describing the error.return 1;: Exits the program with a status code of1, indicating an error.
6. Set Socket Options:
int reuse = 1;
    if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0) {
        printf("SO_REUSEADDR failed: %s \n", strerror(errno));
        return 1;
    }int reuse = 1;: Initializes an integer variablereuseto1.setsockopt: Sets options on the socket.server_fd: The socket file descriptor.SOL_SOCKET: Specifies that the option is at the socket level.SO_REUSEADDR: Allows the socket to bind to an address that is in aTIME_WAITstate, without waiting for its natural timeout to expire. This is useful for server applications that need to restart and bind to the same port.&reuse: A pointer to the value of the option.sizeof(reuse): The size of the option value.
if (setsockopt(...) < 0) { ... }: Checks if setting the socket option failed. Ifsetsockoptreturns-1, an error occurred.
7. Define Server Address:
struct sockaddr_in serv_addr = {
        .sin_family = AF_INET,
        .sin_port = htons(6379),
        .sin_addr = { htonl(INADDR_ANY) },
    };struct sockaddr_in serv_addr = { ... };: Initializes asockaddr_instructure to specify the server's address..sin_family = AF_INET: Sets the address family to IPv4..sin_port = htons(6379): Sets the port number to6379.htons(host to network short) converts the port number from host byte order to network byte order, ensuring compatibility across different systems..sin_addr = { htonl(INADDR_ANY) }: Sets the IP address to accept connections from any interface.htonl(host to network long) converts the address to network byte order.INADDR_ANYis a constant that allows the server to accept connections on any of the host
Last updated