Overview
Socket programming is a technique for developing networked applications that use sockets to communicate over a network. A socket is a computer network endpoint for sending and receiving data.
A socket is used by the client and server in socket programming to communicate with each other. The client makes a request to the server, and the server responds with the information requested. This communication can be synchronous (blocking) or asynchronous (non-blocking).
One advantage of socket programming is that it enables the development of networked applications that can communicate with one another regardless of the underlying operating system or hardware platform. This makes it an effective tool for developing distributed systems and applications that can communicate across a wide area network (WAN).
Sockets are classified into two types: stream sockets and datagram sockets. Stream sockets are TCP/IP-based connections that provide a dependable, stream-oriented connection between the client and server. They are appropriate for applications that require consistent data delivery, such as file transfer and email.
Datagram sockets communicate between the client and server using the UDP/IP protocol and are connectionless. They are appropriate for applications that require fast data transmission, such as real-time audio and video streaming, but do not require reliable data delivery.
The first step in creating a socket in a client-server application is to create a socket descriptor with the socket()
function. This function accepts three arguments: the address family (AF_INET for IPV4 and AF_INET6 for IPV6), the type of socket (SOCK STREAM for stream sockets and SOCK DGRAM for datagram sockets), and the protocol (IPV4 or IPV6) (usually 0, which allows the operating system to choose the appropriate protocol).
Once the socket descriptor has been created, the server must use the bind()
function to bind the socket to a specific port and address. The client then uses the connect()
function to connect to the server.
Following the establishment of the connection, the client and server can exchange data using the send()
and recv()
functions. When the communication is finished, the client and server should use the close()
function to close the socket.
Socket programming is a powerful tool for developing networked applications that is used in a wide range of applications and systems. Developers can create robust and scalable network-capable applications with a solid understanding of socket programming and its underlying principles.
Examples
Server
#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
// Main function for the server
int main(int argc, char *argv[]) {
int socket_desc, client_sock, c, read_size;
struct sockaddr_in server, client;
// Initialize the message buffer to 0
char client_message[2000] = {0};
// Create socket
socket_desc = socket(AF_INET, SOCK_STREAM, 0);
if (socket_desc == -1) {
printf("Could not create socket");
}
puts("Socket created");
// Prepare the sockaddr_in structure
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons(8888);
// Bind
if (bind(socket_desc, (struct sockaddr *)&server, sizeof(server)) < 0) {
// print the error message
perror("bind failed. Error");
return 1;
}
puts("bind done");
// Listen
listen(socket_desc, 3);
// Accept and incoming connection
puts("Waiting for incoming connections...");
c = sizeof(struct sockaddr_in);
// accept connection from an incoming client
client_sock =
accept(socket_desc, (struct sockaddr *)&client, (socklen_t *)&c);
if (client_sock < 0) {
perror("accept failed");
return 1;
} puts("Connection accepted");
// Receive a message from client
while ((read_size = recv(client_sock, client_message, 2000, 0)) > 0) {
// fix garbled message after first message
client_message[read_size] = '\0';
// Echo the message back to the client
write(client_sock, client_message, strlen(client_message));
// Clear the message buffer
memset(client_message, 0, 2000);
}
// Check if client disconnected
if (read_size == 0) {
puts("Client disconnected");
fflush(stdout);
}else if (read_size == -1) {
perror("recv failed");
}
return 0;
}
Client
#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
// Main function for the client
int main(int argc, char *argv[]) {
int sock;
struct sockaddr_in server;
char message[1000], server_reply[2000];
// Create socket
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock == -1) {
printf("Could not create socket");
} puts("Socket created");
// Prepare the sockaddr_in structure
server.sin_addr.s_addr = inet_addr("127.0.0.1");
server.sin_family = AF_INET;
server.sin_port = htons(8888);
// Connect to remote server retrying every 5 seconds if connection fails and print status
while (connect(sock, (struct sockaddr *)&server, sizeof(server)) < 0) {
printf("Connection failed. Retrying in 5 seconds...\n");
sleep(5);
}
puts("Connected\n");
// keep communicating with server
while (1) {
// get multiple words input from user
printf("Enter message : ");
fgets(message, 1000, stdin);
// Send some data
if (send(sock, message, strlen(message), 0) < 0) {
puts("Send failed");
return 1;
}
// Clear the message buffer
memset(message, 0, 1000);
// Receive a reply from the server
if (recv(sock, server_reply, 2000, 0) < 0) {
puts("recv failed");
break;
}
// Print the server's reply
printf("Server reply :");
puts(server_reply);
// Clear the message buffer
memset(server_reply, 0, 2000);
}
// close the socket
close(sock);
return 0;
}