In the modern era, computer networks are crucial for facilitating data transmission. Understanding this area is essential for every developer. Within the realm of computer networking, socket programming stands out as a fundamental concept in the programming domain. This discussion will delve into socket programming in C++ and explore various techniques employed in this field.
In C++, socket programming is a technique that establishes communication between multiple nodes across a network, enabling seamless data sharing without any loss. Within this communication setup, one node is designated to listen on a specific port associated with a particular IP address. Upon client connection to the server, the server initiates the socket listener.
What is a Socket?
Let's explore the concept of a socket through a practical scenario. A socket serves as a communication channel between two devices. For instance, a socket could resemble a phone charger establishing a link between the charger and a phone, or a connection between a phone and a laptop. By utilizing a socket, various applications can connect to the local network through distinct ports. Upon socket creation, the server designates the program, which in turn identifies the socket and the domain address.
The socket represents a mechanism utilized for transferring data between various processes. These processes may exist on separate devices or on the same device that are linked via a network. Upon establishing the socket connection, data can be transmitted bidirectionally and will persist until one of the endpoints terminates the connection.
Procedure in Client-Server Communication
There are some procedures that we have to follow to establish client-server communication. These are as follows.
- Socket: With the help of a socket, we can create a new communication.
- Bind: With the help of this we can, we can attach the local address with the socket.
- Listen: With this help; we can accept the connection.
- Accept: With this help; we can block the incoming connection until the request arrives.
- Connect: With this help; we can attempt to establish the connection.
- Send: With the help of this; we can send the data over the network.
- Receive: With this help; we can receive the data over the network.
- Close: With the help of this, we can release the connection from the network.
Stages for Server Socket Creation
There are some stages by which we can create the socket for the server. These are as follows.
- int socketcr: Socket(domain, type, protocol)
- Socketcr: It is an integer type, and it is like a file handler.
- Domain: It is a communication domain and it is an integer type.
- Type: It is a communication type.
- SOCK_DGRAM: It is a type of UDP which is unreliable and connectionless.
- Protocol: It is used to assign the protocol value for the IP address, which is 0. The protocol value is similar to the value appearing in the protocol field of the IP header of the pocket.
What is a Connection?
A connection refers to a form of association between two devices where both pieces of software are mutually aware of each other. These software components possess the capability to initiate a connection with each other, indicating their ability to transmit data across the network. A socket connection entails that both devices possess complete information about each other, including details such as the IP address, TCP port, and other relevant communication parameters.
A socket is an object that resembles a file and enables a program to accept incoming connections, as well as send and receive data through these connections. Additionally, it represents a resource allocated to the server's process.
The server can create the socket with the help of the socket. This socket can not be shared with any other processor.
- Setsockopt: With the help of Setsockopt, we can manipulate the various option of the socket, which are referred to by the socket's file descriptor. This process is completely optional. With the help of Setsockopt, we can reuse the port and address of the client and the server. When the server gives the error " address already in use," we can prevent it with the help of Setsockopt.
- Bind: We can bind the socket with the address and the port with the help of the bind function. This operation is done after the creation of the socket. For example, if we try to bind the server with the local host, then we use INADDR_ANY to define the server's IP address.
- Listen: We can make a connection mode socket with the help of the listening to function. An example of a connection mode socket is SOCK_STREAM. This can be defined by the socket argument. This is used to accept the incoming connection perform the queue operation for the incoming connection, and perform the backlog of the incoming connection. When an incoming connection requests the server for acknowledgment, the socket is put into passive mode. The backlog parameter of the server refers to the fact that it cannot allow more than one connection at a time to the server. If some incoming connection has come and the queue is full, then the server provides the error with an indication of " ECONNREFUSED." With the help of listen, the incoming connection is on hold, and when the queue is empty, it calls all the incoming connections to the server.
- Accept: With the help of accept system call; we can make the connection-based socket. Some connection-based sockets are SOCKSTREAMand SOCKSEQPACKET. It extracts all the incoming connections that come in first and allows their request to go to the server. The newly connected list is not able to listen with the help of another argument for the creation of the new socket.
- Socket connection: It is exactly the same as the method for the creation of the server.
- Connect: We can initiate a connection to the socket with the help of connect system call. If the parameter for the socket is a type of SOCKDGRAM, then we can define the datagram as permanent with the help of connect. If the socket is of type SOCKSTREAM, then we can attempt to make another connection for the server. With the help of connect function, we can also create a connection for the foreign association. If the socket is unbound, then the system assigns the unique value to the local association. When the system successfully calls completed, the socket is ready to send or receive any type of data.
- Send/Receive: The send and recv functions can perform the below operation.
- The socket on which the data can be communicated with each other.
- The storage buffer can store data about the address, like addrofdata and addrofbuffer.
- It deals with the size of the buffer, like lenofdata and lenofbuffer.
- It deals with the flag that says how the data will be sent.
Stages for Client
Steps to Establish the Connection in the Socket
It establishes a communication link between various clients and the server. However, both the client and the server are capable of managing the socket connection. Each individual process must create a connection for its respective socket.
The steps involved in establishing a socket on the client side are as follows:
- It creates a socket with the help of a socket system call.
- Then we have to connect with the socket address of the server with the help of a system call.
- Then we have to send and receive the data. We can do this in various ways. we can do this read and write function.
The steps involved in establishing a socket on the server side are as follows:
- It first creates a socket with the help of a socket system call.
- Then it binds the socket to an address with the help of the bind system call. An address consists of a port number for the server socket in the host machine.
- Then it listens for the connection with the help of the listening system call.
- Then the server accepts the incoming connection with the help of accept system call. It also blocks all incoming commands until a client is connected to a server.
- Then the process of sending and receiving data starts.
Connecting Multiple Clients without Multithreading
There are numerous instances where we observe the interaction of an individual user with the server. In the current landscape of programming, the server accommodates multiple users concurrently through distinct sockets.
There are multiple methods to accomplish this task. One such approach involves utilizing multithreading. By employing multithreading, we can successfully execute this task. The implementation of a multithreading mechanism can be achieved through utilizing the select function.
Example:
Code for the client:
// 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 sock = 0, valread, client_fd;
struct sockaddr_in serv_addr;
char* hello = "Hello from client";
char buffer[1024] = { 0 };
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, "127.0.0.1", &serv_addr.sin_addr)
<= 0) {
printf(
"\nInvalid address/ Address not supported \n");
return -1;
}
if ((client_fd
= connect(sock, (struct sockaddr*)&serv_addr,
sizeof(serv_addr)))
< 0) {
printf("\nConnection Failed \n");
return -1;
}
send(sock, hello, strlen(hello), 0);
printf("Hello message sent\n");
valread = read(sock, buffer, 1024);
printf("%s\n", buffer);
// closing the connected socket
close(client_fd);
return 0;
}
Code for server:
// 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, valread;
struct sockaddr_in address;
int opt = 1;
int 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 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 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,
(socklen_t*)&addrlen))
< 0) {
perror("accept");
exit(EXIT_FAILURE);
}
valread = read(new_socket, buffer, 1024);
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
shutdown(server_fd, SHUT_RDWR);
return 0;
}
Compiling:
Output:
Uses of Socket Programming
Socket programs are commonly employed for facilitating communication between different processes, often operating on separate systems. They are primarily utilized for establishing a client-server architecture. This article outlines the diverse functions involved in developing both the server and client applications, along with a sample program.
In this scenario, the customer application transmits a filename to the server, which then transmits the file's content back to the customer. Socket development typically involves fundamental communication protocols such as TCP/UDP and low-level sockets like ICMP. These protocols exhibit minimal communication overhead in contrast to underlying protocols like HTTP, DHCP, SMTP, etc.
Some of the basic data communications between the client and server are:
- File Transfer: Sends name and gets a file.
- Web Page: Sends URL and gets a page.
- Echo: Sends a message and gets it back.
- C++ can establish communication only with the machine requested and not with any other machine on the network.
- Sockets allow only raw data to be sent. This means that the client and server need mechanisms to interpret the data.