Socket acts as an endpoint for sending and receiving data between two programs over a network. They form the backbone of inter-process communication and work at the transport layer (OSI layer 4). For a socket to work at the transport layer, it must provide a communication channel between two devices over a network by using transport protocols like TCP and UDP.
Sockets are essential for network communication, allowing applications to send and receive data over the internet or local networks. Whether you're browsing the web, streaming a video, or playing an online game, sockets make it happen
Different type of socket
As you'll see, different types of sockets serve different purposes depending on your needs. While I'll focus on TCP and UDP sockets, it's worth mentioning that the transport layer also includes Raw sockets.
Stream Sockets (TCP)
A TCP socket is a connection-oriented socket that ensures reliable communication between a client and a server. By 'reliable', it means that it ensures the data arrives completely and in order. However, this also means it's slower due to an extra overhead from reliabiliy mechanisms. Additionally, it performs error-checking on the packets to ensure data integrity.
TCP is reliable, sends packets in order, checks for errors but is slower.
Use Cases
- Web browsing
- File transfer
- Database connections
// TCP server (C++)
#include <iostream>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
int main() {
int server_fd, new_socket;
struct sockaddr_in address;
int addrlen = sizeof(address);
// Create a TCP socket (SOCK_STREAM)
server_fd = socket(AF_INET, SOCK_STREAM, 0);
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(8080);
// Bind and listen
bind(server_fd, (struct sockaddr*)&address, sizeof(address));
listen(server_fd, 3);
std::cout << "Waiting for connection..." << std::endl;
// Accept connection
new_socket = accept(server_fd, (struct sockaddr*)&address, (socklen_t*)&addrlen);
std::cout << "Connection established!" << std::endl;
close(new_socket);
close(server_fd);
return 0;
}
// TCP Client (C++)
#include <iostream>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
int main() {
int sock = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in serv_addr;
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(8080);
inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr);
// Connect to server
connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
std::cout << "Connected to server!" << std::endl;
close(sock);
return 0;
}
Datagram Sockets (UDP)
A UDP socket is a connectionless socket that sends data as individual packets, without ensuring they are received in order or at all. UDP prioritizes speed, as error checking introduces delays in the process. Compared to TCP, UDP does not form a connection with the server but instead sends a datagram. In UDP, it is possible to call the connect() function, but it does not behave like it does in TCP.
UDP is fast, has low latency but is unreliable.
Use Cases
- Online gaming
- VoIP (Skype, Zoom, Discord voice calls, ...)
- Live video streaming
- DNS
// UDP Server (C++)
#include <iostream>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
int main() {
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
struct sockaddr_in serv_addr, cli_addr;
socklen_t cli_len = sizeof(cli_addr);
char buffer[1024];
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(8080);
// Bind the socket
bind(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
std::cout << "Waiting for UDP message..." << std::endl;
// Receive message
recvfrom(sockfd, buffer, sizeof(buffer), 0, (struct sockaddr*)&cli_addr, &cli_len);
std::cout << "Received: " << buffer << std::endl;
close(sockfd);
return 0;
}
// UDP Client (C++)
#include <iostream>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <cstring>
int main() {
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
struct sockaddr_in serv_addr;
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(8080);
inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr);
char message[] = "Hello, UDP!";
sendto(sockfd, message, strlen(message), 0, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
std::cout << "Message sent!" << std::endl;
close(sockfd);
return 0;
}
TCP vs. UDP: Key Differences
Now that we understand the basics of TCP and UDP, let's compare them side by side to highlight their key differences more clearly:
| Feature | TCP (Stream Socket) | UDP (Datagram Socket) |
|---|---|---|
| Connection | Requires handshake (stateful) | No handshake (stateless) |
| Reliability | Reliable (ensures delivery) | Unreliable (packets can be lost) |
| Ordering | Guarantees correct order | Packets may arrive out of order |
| Speed | Slower due to error-checking | Faster (no extra overhead) |
| Use Cases | Web browsing, file transfer, email | Gaming, VoIP, live streaming |
When to Use TCP vs. UDP
| Scenario | Best Choice | Reason |
|---|---|---|
| Web browsing | TCP | Ensures reliable page loading |
| Video calls (VoIP) | UDP | Low latency is more important than reliability |
| File transfer | TCP | Data integrity is crucial |
| Online gaming | UDP | Speed is more important than reliability |
| DNS queries | UDP | Quick, lightweight requests |
Conclusion
Sockets are the foundation of network communication, enabling data exchange between different networks. TCP sockets provide reliable, connection-oriented communication, while UDP sockets offer fast, connectionless data transfer.
Choosing between TCP and UDP depends on the needs of your application—TCP is best for reliability, such as in web browsing and file transfers, while UDP excels in real-time, low-latency scenarios like online gaming and VoIP.
Understanding how sockets work is essential for any developer working with networked applications. Whether you're building a simple chat server, a multiplayer game, or a large-scale web service, knowing how to use TCP and UDP effectively will help you create efficient and scalable systems.


