
Sockets (Stream Sockets and Datagram Sockets)
A socket is an endpoint for two-way communication between two programs, typically running on the same machine or across different machines in a network.
There are two main types of sockets:
- Stream socket (TCP): Uses the Transmission Control Protocol (TCP) to provide a reliable, ordered, and error-checked stream of bytes between two programs. TCP ensures data arrives in the same order it was sent.
- Datagram socket (UDP): Uses the User Datagram Protocol (UDP), which is connectionless and does not guarantee delivery or ordering of packets. It is faster than TCP but less reliable. Some implementations add timeouts or retries for error handling.
Sockets are identified by a combination of:
- An IP address (identifies the machine), and
- A port number (identifies the specific process/service on that machine).
Sockets are accessed through system calls (APIs) provided by the operating system.
Important socket system calls
int socket(int domain, int type, int protocol);
→ Creates a new socket and returns a file descriptor (an integer that identifies the socket).
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
→ Associates a socket with an address (IP + port).
int close(int sockfd);
→ Closes a socket and frees associated resources.
Typical Workflow
Server-Side Flow (TCP)
socket()→ create socket.bind()→ assign IP address + port to socket.listen()→ mark as listening for connections.accept()→ accept an incoming connection.read() / write()→ exchange data.close()→ free resources.
Client-Side Flow (TCP)
socket()→ create socket.connect()→ connect to server IP + port.read() / write()→ exchange data.close()→ free resources.
UDP Flow (simpler, no connection setup)
socket()→ create socket.bind()→ optional, assign local port.sendto()→ send a message to destination.recvfrom()→ receive a message.close()→ free resources.

1. TCP Stream Socket (Connection-Oriented)
TCP is connection-based, meaning the server must listen() for incoming
requests and explicitly accept() a client connection before data exchange can occur.
// TCP socket creation
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
perror("Error creating TCP socket");
exit(EXIT_FAILURE);
}
// Fill in server address structure
struct sockaddr_in serverAddr{};
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = INADDR_ANY; // Listen on all interfaces
serverAddr.sin_port = htons(8080); // Port number - source port must be explicitly specified
// Bind to the specified address and port
if (bind(sockfd, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) < 0) {
perror(“Bind failed”);
close(sockfd);
exit(EXIT_FAILURE);
}
// Mark socket as passive (ready to accept connections)
if (listen(sockfd, 5) < 0) {
perror(“Listen failed”);
close(sockfd);
exit(EXIT_FAILURE);
}
// Accept a client connection
struct sockaddr_in clientAddr{};
socklen_t clientLen = sizeof(clientAddr);
int clientSock = accept(sockfd, (struct sockaddr*)&clientAddr, &clientLen);
if (clientSock < 0) {
perror(“Accept failed”);
close(sockfd);
exit(EXIT_FAILURE);
}
printf(“TCP connection established!\n”);
2. UDP Datagram Socket (Connectionless)
UDP is connectionless and does not guarantee delivery, ordering, or reliability. However, it is much faster and is often used for real-time applications like online gaming, video streaming, etc.
// UDP socket creation
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0) {
perror("Error creating UDP socket");
exit(EXIT_FAILURE);
}
// Fill in server address structure
struct sockaddr_in serverAddr{};
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = INADDR_ANY;
serverAddr.sin_port = htons(8080);
// Bind to the specified address and port
if (bind(sockfd, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) < 0) {
perror(“Bind failed”);
close(sockfd);
exit(EXIT_FAILURE);
}
printf(“UDP server listening on port 8080…\n”);
// Receive a datagram from any client
char buffer[1024];
struct sockaddr_in clientAddr{};
socklen_t clientLen = sizeof(clientAddr);
int n = recvfrom(sockfd, buffer, sizeof(buffer), 0,
(struct sockaddr*)&clientAddr, &clientLen);
if (n < 0) {
perror(“recvfrom failed”);
close(sockfd);
exit(EXIT_FAILURE);
}
buffer[n] = ‘\0’;
printf(“Received UDP datagram: %s\n”, buffer);
// Send a reply
const char* reply = “Message received!”;
sendto(sockfd, reply, strlen(reply), 0,
(struct sockaddr*)&clientAddr, clientLen);

















