TCP/IP Protocol Stack Programming in C Language

In modern network communication, the TCP/IP protocol stack is one of the most important foundations. It provides a standardized method for communication between computers. In this article, we will delve into how to perform TCP/IP programming using the C language, demonstrating basic client and server implementations through example code.

1. Overview of TCP/IP Protocol Stack

TCP/IP (Transmission Control Protocol/Internet Protocol) is a set of protocols used for network communication. It is divided into four layers:

  • Application Layer: Handles data for specific applications, such as HTTP, FTP, etc.
  • Transport Layer: Responsible for the reliability and order of data transmission, mainly TCP and UDP.
  • Network Layer: Responsible for routing data packets across the network, primarily using IP.
  • Link Layer: Handles physical connections and data frames.

In this tutorial, we will focus on the interaction between the application layer and the transport layer, implementing a simple TCP client and server in C language.

2. Environment Setup

Ensure that your development environment has a C compiler (such as GCC) and the necessary development libraries installed. On Linux systems, you can compile and run directly from the terminal.

3. TCP Server Implementation

Below is a simple example of TCP server code that listens on a specified port and accepts messages from clients:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#define PORT 8080
#define BUFFER_SIZE 1024
int main() {
    int server_fd, new_socket;
    struct sockaddr_in address;
    int opt = 1;
    int addrlen = sizeof(address);
    char buffer[BUFFER_SIZE] = {0};
    // Create socket
    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
        perror("socket failed");
        exit(EXIT_FAILURE);
    }
    // Set socket options to allow address reuse
    if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) {
        perror("setsockopt");
        exit(EXIT_FAILURE);
    }
    // Set address structure
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY; // Accept any IP address
    address.sin_port = htons(PORT); // Convert to network byte order
    // Bind socket to specified port
    if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
        perror("bind failed");
        exit(EXIT_FAILURE);
    }
    // Start listening for connection requests
    if (listen(server_fd, 3) < 0) {
        perror("listen");
        exit(EXIT_FAILURE);
    }
    printf("Waiting for connections...\n");
    while(1) {
        // Accept new connection requests
        if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) {
            perror("accept");
            exit(EXIT_FAILURE);
        }
        read(new_socket , buffer, BUFFER_SIZE);
        printf("Received message: %s\n", buffer);
        const char *response = "Message received";
        send(new_socket , response , strlen(response), 0 );
        close(new_socket);
    }
    return 0;
}

Program Explanation:

  1. Create a socket and set options to allow address reuse.
  2. Use the <span>bind()</span> function to bind the socket to the specified port.
  3. Call <span>listen()</span> to start listening for connection requests.
  4. In a loop, accept new connections from clients, read the sent messages, and return a response.

4. TCP Client Implementation

Below is a simple example of TCP client code that sends a message to the server and waits for a response:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#define PORT 8080
#define BUFFER_SIZE 1024
int main() {
     int sock = 0;
     struct sockaddr_in serv_addr;
     char *message = "Hello, Server!";
     char buffer[BUFFER_SIZE] = {0};
     // Create socket file descriptor
     if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
         printf("\n Socket creation failed \n");
         return -1;
     }
     serv_addr.sin_family = AF_INET;
     serv_addr.sin_port = htons(PORT);
     // Convert IPv4 address from text to binary form
     if(inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0) {
          printf("\n Invalid address/ Address not supported \n");
          return -1;
     }
     // Attempt to connect to the server
     if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
           printf("\n Connection failed \n");
           return -1;
     }
     send(sock , message , strlen(message), MSG_NOSIGNAL);
     read(sock , buffer , BUFFER_SIZE);
     printf("%s\n", buffer);
     close(sock);
     return 0;
}

Program Explanation:

  1. Create a socket for communication with the server.
  2. Set the target server information, including IP address and port number.
  3. Use the <span>connect()</span> function to attempt to establish a connection with the server.
  4. Send a message to the server and read the information returned by the server.

Conclusion

Through the above two simple examples, we have demonstrated how to perform basic TCP/IP programming using the C language. You can expand these codes according to your needs, such as adding multi-threading support, error handling mechanisms, etc. These foundational knowledge are crucial for understanding more complex network applications, and we hope this article helps you get started with TCP/IP programming in C language!

Leave a Comment