Hey guys! Let's dive into creating a simple daytime client-server program using C. This is a classic example that illustrates basic networking concepts, and it's perfect for beginners who want to understand how clients and servers communicate. We'll break down the code step-by-step, making it super easy to follow along. So, grab your favorite text editor, and let's get started!

    What is a Daytime Client-Server Program?

    Before we jump into the code, let's understand what we're building. A daytime client-server program is designed to provide the current date and time from a server to any client that requests it. The server listens for incoming connections on a specific port, and when a client connects, the server sends the current date and time. It's a straightforward example that demonstrates the fundamental principles of client-server architecture.

    The daytime server acts as a central source of time information. Clients, on the other hand, connect to the server to retrieve this information. This interaction showcases the basic request-response model that underlies much of network communication. Implementing such a program in C allows us to delve into socket programming, which is crucial for building networked applications.

    In essence, this program serves as an excellent educational tool for grasping how data is transmitted over a network. It highlights the roles of both the client and the server in a networked environment, demonstrating how they interact to fulfill a simple yet practical task. By understanding this fundamental example, you can build a solid foundation for more complex network programming projects.

    Setting Up the Server

    First, let's create the server-side code. The server needs to listen for incoming connections and, upon receiving a connection, send the current date and time to the client. Here's a breakdown of the code:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <time.h>
    #include <unistd.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    
    #define PORT 13 // Daytime port
    
    int main() {
        int server_fd, new_socket;
        struct sockaddr_in address;
        int addrlen = sizeof(address);
        char buffer[1024] = {0};
        time_t timer;
        char *time_string;
    
        // Creating socket file descriptor
        if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
            perror("socket failed");
            exit(EXIT_FAILURE);
        }
    
        address.sin_family = AF_INET;
        address.sin_addr.s_addr = INADDR_ANY;
        address.sin_port = htons(PORT);
    
        // Binding the socket to the specified address and port
        if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
            perror("bind failed");
            exit(EXIT_FAILURE);
        }
    
        // Listening for incoming connections
        if (listen(server_fd, 3) < 0) {
            perror("listen failed");
            exit(EXIT_FAILURE);
        }
    
        printf("Server listening on port %d\n", PORT);
    
        // Accepting incoming connections
        if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen))<0) {
            perror("accept failed");
            exit(EXIT_FAILURE);
        }
    
        // Get current time
        timer = time(NULL);
        time_string = ctime(&timer);
    
        // Send time to client
        send(new_socket, time_string, strlen(time_string), 0);
        printf("Time sent to client: %s", time_string);
        close(new_socket);
        close(server_fd);
    
        return 0;
    }
    

    Code Explanation

    1. Include Headers: The code starts by including necessary header files such as stdio.h, stdlib.h, string.h, time.h, unistd.h, sys/socket.h, and netinet/in.h. These headers provide functions for standard input/output, memory allocation, string manipulation, time management, process control, socket programming, and internet protocol support.
    2. Define Port: The PORT macro is defined as 13, which is the standard port for the Daytime service. This port number is used by both the server and the client to establish a connection.
    3. Create Socket: The socket() function creates a new socket file descriptor. AF_INET specifies the IPv4 address family, SOCK_STREAM indicates a TCP socket, and 0 selects the default protocol.
    4. Bind Socket: The bind() function assigns the socket to a specific address and port. The sockaddr_in structure is used to define the address, with sin_family set to AF_INET, sin_addr.s_addr set to INADDR_ANY (allowing the server to listen on all available interfaces), and sin_port set to the specified PORT.
    5. Listen for Connections: The listen() function puts the socket in a passive listening state, waiting for incoming connections. The second argument, 3, specifies the maximum length of the queue for pending connections.
    6. Accept Connection: The accept() function accepts an incoming connection, creating a new socket for the connection. The new_socket variable holds the file descriptor for this new socket.
    7. Get Current Time: The time() function retrieves the current time as a time_t value. The ctime() function converts this value into a human-readable string.
    8. Send Time to Client: The send() function transmits the current time string to the client through the new_socket. The strlen() function calculates the length of the time string to be sent.
    9. Close Sockets: The close() function closes both the new_socket (the socket used for the connection with the client) and the server_fd (the original server socket).

    Building the Client

    Now, let's create the client-side code. The client needs to connect to the server and display the date and time received. Here’s how it looks:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    
    #define PORT 13 // Daytime port
    #define SERVER_IP "127.0.0.1" // localhost
    
    int main() {
        int sock = 0;
        struct sockaddr_in serv_addr;
        char buffer[1024] = {0};
    
        // Creating socket file descriptor
        if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
            printf("\n Socket creation error \n");
            return -1;
        }
    
        serv_addr.sin_family = AF_INET;
        serv_addr.sin_port = htons(PORT);
    
        // Convert IPv4 and IPv6 addresses from text to binary form
        if(inet_pton(AF_INET, SERVER_IP, &serv_addr.sin_addr)<=0) {
            printf("\nInvalid address/ Address not supported \n");
            return -1;
        }
    
        // Connecting to the server
        if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
            printf("\nConnection Failed \n");
            return -1;
        }
    
        // Read time from server
        read(sock, buffer, 1024);
        printf("Time from server: %s\n", buffer);
    
        close(sock);
        return 0;
    }
    

    Code Explanation

    1. Include Headers: Just like the server, the client includes necessary header files for input/output, string manipulation, socket programming, and internet protocol support.
    2. Define Port and Server IP: The PORT macro is defined as 13, matching the server's port. SERVER_IP is defined as `