Socket Programming In C/C++

Socket Programming in C/C++

Socket programming is a method for enabling communication between two nodes on a network. One node, acting as a server, listens on a specific port at an IP address. The other node, functioning as a client, initiates a connection to the server. In this communication setup, the server establishes a listener socket, and the client initiates contact with the server.

1. Socket creation:

In socket programming, the socket function is used with the following parameters:

  • sockfd: Socket descriptor, represented as an integer, similar to a file handle.
  • domain: An integer specifying the communication domain. Examples include AF_LOCAL for communication between processes on the same host, AF_INET for processes connected by IPV4, and AF_INET6 for processes connected by IPV6.
  • type: Communication type, where SOCK_STREAM is used for TCP (reliable and connection-oriented) and SOCK_DGRAM is used for UDP (unreliable and connectionless).
  • protocol: The protocol value for Internet Protocol (IP), typically set to 0. This value corresponds to the protocol field in the IP header of a packet.

For instance, when creating a TCP socket for communication between processes on different hosts connected by IPV4, the socket function might be called with parameters like this:

int sockfd = socket(AF_INET, SOCK_STREAM, 0);

This line creates a socket descriptor (sockfd) for a TCP socket using the Internet Protocol version 4 (AF_INET) and the reliable, connection-oriented communication type (SOCK_STREAM). The protocol field is set to 0, indicating that the default protocol for the specified domain and type should be used.

2. Setsockopt:

manipulating socket options for the file descriptor sockfd is an optional yet valuable practice in socket programming. It allows for the customization of socket behavior, particularly aiding in the reuse of addresses and ports. This is particularly useful in preventing errors such as “address already in use,” ensuring smoother execution and better handling of network resources.

int setsockopt(int sockfd, int level, int optname,  const void *optval, socklen_t optlen);

3. Bind:

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

After making the socket, the “bind” function links it to a specific address and port number provided in the “addr” (custom data structure). In the example code, we connect the server to the localhost, so we use INADDR_ANY to indicate the IP address.

4. Listen:

int listen(int sockfd, int backlog);

a.passive Mode:

  • Putting the server socket in passive mode means that the socket is ready to accept incoming connection requests from clients.
  • This is typically done using the listen function in the Berkeley Sockets API.

b.Backlog:

  • The listen function takes a second parameter, which is the backlog. This parameter defines the maximum length of the queue of pending connections for the specified socket (sockfd).
  • The backlog essentially represents the maximum number of clients that can wait to be served by the server.

c.Handling Connection Requests:

  • When a client attempts to connect to the server, the server accepts the connection request and establishes a connection.
  • If the number of pending connection requests in the queue exceeds the backlog value, additional connection requests may be refused.
  • The client may receive an error with the indication ECONNREFUSED if the queue is full.

5. Accept:

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

This process involves accepting the first connection request in the queue for the listening socket (sockfd). It creates a new connected socket and returns a file descriptor for that socket. This marks the establishment of a connection between the client and server, ready for data transfer.

Stages For Client

a.Socket Connection:

  • The process of creating a socket connection is identical to that of the server’s socket creation.
  • It involves using a system call (e.g., socket()) to create a socket, specifying the address family, socket type, and protocol.

b.Connect System Call:

  • The connect() system call is used to establish a connection for a socket.
  • It takes the socket file descriptor (sockfd) and the address (addr) to which the connection should be made.
  • In the context of a client connecting to a server, the server’s address and port are typically specified in addr.
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

Implementation

One hello message is being exchanged between server and client and this could enable to illustrate the client/server model.

Server.c

/ Server side C/C++ program to demonstrate Socket
// programming
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#define PORT 8080
int main(int argc, char const* argv[])
{
    int server_fd, new_socket;
    ssize_t valread;
    struct sockaddr_in address;
    int opt = 1;
    socklen_t addrlen = sizeof(address);
    char buffer[1024] = { 0 };
    char* hello = "Hello from server";
 
    // Creating socket file descriptor
    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        perror("socket failed");
        exit(EXIT_FAILURE);
    }
 
    // Forcefully attaching socket to the port 8080
    if (setsockopt(server_fd, SOL_SOCKET,
                   SO_REUSEADDR | SO_REUSEPORT, &opt,
                   sizeof(opt))) {
        perror("setsockopt");
        exit(EXIT_FAILURE);
    }
address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port = htons(PORT);
 
    // Forcefully attaching socket to the port 8080
    if (bind(server_fd, (struct sockaddr*)&address,
             sizeof(address))
        < 0) {
        perror("bind failed");
        exit(EXIT_FAILURE);
    }
    if (listen(server_fd, 3) < 0) {
        perror("listen");
        exit(EXIT_FAILURE);
    }
    if ((new_socket
         = accept(server_fd, (struct sockaddr*)&address,
                  &addrlen))
        < 0) {
        perror("accept");
        exit(EXIT_FAILURE);
    }
    valread = read(new_socket, buffer,
                   1024 - 1); // subtract 1 for the null
                              // terminator at the end
    printf("%s\n", buffer);
    send(new_socket, hello, strlen(hello), 0);
    printf("Hello message sent\n");
 
    // closing the connected socket
    close(new_socket);
    // closing the listening socket
    close(server_fd);
    return 0;
}

client.c

// Client side C/C++ program to demonstrate Socket
// programming
#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#define PORT 8080
 
int main(int argc, char const* argv[])
{
    int status, valread, client_fd;
    struct sockaddr_in serv_addr;
    char* hello = "Hello from client";
    char buffer[1024] = { 0 };
    if ((client_fd = 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, "127.0.0.1", &serv_addr.sin_addr)
        <= 0) {
        printf(
            "\nInvalid address/ Address not supported \n");
        return -1;
    }
if ((status
         = connect(client_fd, (struct sockaddr*)&serv_addr,
                   sizeof(serv_addr)))
        < 0) {
        printf("\nConnection Failed \n");
        return -1;
    }
    send(client_fd, hello, strlen(hello), 0);
    printf("Hello message sent\n");
    valread = read(client_fd, buffer, 1024 - 1); // subtract 1 for the null terminator at the end
    printf("%s\n", buffer);
 
    // closing the connected socket
    close(client_fd);
    return 0;
}

Compiling:

gcc client.c -o client
gcc server.c -o server

Output

Client:Hello message sent
Hello from server
Server:Hello from client
Hello message sent

FAQ- Socket Programming in C/C++

Q1. What is the socket method in C++?

Ans. Sockets facilitate network communication between applications by creating a connection between two endpoints. The socket() function, found in languages like C and Python, generates a socket and provides a file descriptor for subsequent referencing. This file descriptor is used to configure and manage communication between devices over the network, with functions like bind() and connect() being employed for further setup. Finally, the close() function is used to terminate the socket when communication is complete.

Q2.What is the syntax of a socket?

Ans. The socket() function is utilized with the signature int socket(int domain, int type, int protocol). The domain parameter determines the communication method, commonly using AF_INET for TCP/IP sockets. The type parameter defines the nature of communication.

Q3. What is socket and its types?

Ans. Datagram Socket: A type of socket that provides a connectionless, message-oriented communication. Datagram sockets are often associated with UDP (User Datagram Protocol).
Stream Socket: This type of socket offers a connection-oriented, reliable, and stream-oriented communication. Stream sockets are commonly used with TCP (Transmission Control Protocol).

Hridhya Manoj

Hello, I’m Hridhya Manoj. I’m passionate about technology and its ever-evolving landscape. With a deep love for writing and a curious mind, I enjoy translating complex concepts into understandable, engaging content. Let’s explore the world of tech together

Leave a Comment