Fundamentals of Network Programming in C: Socket Programming

Fundamentals of Network Programming in C: Socket Programming

In modern computer science, network programming is an important field. As a low-level language, C provides powerful capabilities for network programming. This article will introduce the basics of socket programming in C, helping beginners understand how to perform simple network communication using C.

What is a Socket?

A socket is an interface used to implement communication between different hosts. In a network, data is transmitted through sockets. Each socket has a unique address, including an IP address and a port number. With this information, programs can identify and communicate with other devices.

Types of Sockets

In C, there are two main types of sockets:

  1. Stream Socket (SOCK_STREAM): Used for TCP protocol, providing reliable, connection-oriented data transmission.
  2. Datagram Socket (SOCK_DGRAM): Used for UDP protocol, does not guarantee packet order and integrity, but is faster.

Basic Steps

Network programming in C typically involves the following steps:

  1. Create a socket
  2. Bind the socket to a specific address
  3. Listen for connection requests (for servers)
  4. Accept connection requests (for servers)
  5. Send and receive data
  6. Close the socket

Below, we will demonstrate these steps with example code.

Example Code: TCP Server

The following is a simple TCP server example that listens for client requests and echoes back the received data.

#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 file descriptor
    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
        perror("Socket creation failed");
        exit(EXIT_FAILURE);
    }

    // Set socket options
    if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) {
        perror("Set socket options failed");
        exit(EXIT_FAILURE);
    }

    // Set address structure
    address.sin_family = AF_INET; // IPv4
    address.sin_addr.s_addr = INADDR_ANY; // Any IP address
    address.sin_port = htons(PORT); // Specify port number

    // Bind socket to specified address
    if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
        perror("Bind failed");
        exit(EXIT_FAILURE);
    }

    // Start listening for connection requests, max queue size is 3
    if (listen(server_fd, 3) < 0) {
        perror("Listen failed");
        exit(EXIT_FAILURE);
    }
    printf("Server is listening on port %d\n", PORT);

    while(1) {
        // Accept new connection requests
        if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) {
            perror("Accept failed");
            exit(EXIT_FAILURE);
        }
        printf("Connection accepted\n");
        int valread = read(new_socket, buffer, BUFFER_SIZE);
        printf("%s\n", buffer);
        send(new_socket, buffer, valread, 0);
        printf("Echo message sent\n");
        close(new_socket);
    }
    return 0;
}

Code Explanation

  • Create Socket: Use the <span>socket()</span> function to create a new socket.
  • Set Options: Use the <span>setsockopt()</span> function to set socket options, such as allowing local address reuse.
  • Bind Socket: Use the <span>bind()</span> function to associate the created socket with the specified IP address and port number.
  • Listen for Connections: Use the <span>listen()</span> function to start listening for connection requests from clients.
  • Accept Connection: Use the <span>accept()</span> function to accept connections from clients and return a new socket descriptor for communication with that client.
  • Read and Send Data: Use the <span>read()</span> and <span>send()</span> functions to handle data read from the client and echo it back.

Example Code: TCP Client

Below is a simple TCP client example corresponding to the above server program, which sends a message to the server and prints the 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 *hello = "Hello from client";
    char buffer[BUFFER_SIZE] = {0};

    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < -1) {
        printf("\n Socket creation error \n");
        return -1;
    }

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(PORT);

    // Convert IPv4 string to binary format
    if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= -1) {
        printf("\nInvalid address/ Address not supported \n");
        return -1;
    }

    if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < -1) {
        printf("\nConnection Failed \n");
        return -1;
    }

    send(sock, hello, strlen(hello), MSG_NOSIGNAL);
    read(sock, buffer, BUFFER_SIZE);
    printf("%s\n", buffer);
    close(sock);
    return 0;
}

Client Code Explanation

  • Create Socket: Similarly, use the <span>socket()</span> function to create a new TCP socket.
  • Set Target Address Structure: Fill in the target host’s information, including IP address and port number.
  • Establish Connection: Call the <span>connect()</span> method to attempt to establish a link with the specified server. If successful, data can be sent or received.
  • Send and Read Data: Use the <span>send()</span> function to send a message to the server and the <span>read()</span> function to retrieve the data returned by the server, then print it out.

Conclusion

This article introduced the basic concepts of network programming in C and their implementation methods, demonstrating how to use sockets for basic data transmission through simple TCP server and client examples. This knowledge lays the foundation for further learning of more complex network applications. In actual development, you also need to consider error handling, performance optimization, and other issues. I hope this article helps you get started.

Leave a Comment