What is a Socket?
A socket is a software endpoint that opens a two-way communication link between two programs running on a network. It serves as an abstraction for sending and receiving data across machines.
How Do Sockets Work?
To communicate over a network:
- The server creates a socket and waits for incoming requests.
- The client creates a socket and connects to the server’s socket.
- Once connected, they exchange data over that socket connection.
This applies to both TCP (connection-oriented) and UDP (connectionless) protocols.
Types of Sockets in C/C++
- Stream Sockets (
SOCK_STREAM
)- Used for TCP
- Ensures reliable, ordered, and error-checked delivery
- Suitable for file transfers, web servers, etc.
- Datagram Sockets (
SOCK_DGRAM
)- Used for UDP
- Faster, connectionless, but less reliable
- Ideal for real-time apps (games, video calls)
- Raw Sockets (
SOCK_RAW
)- Gives direct access to lower-layer protocols (IP, ICMP)
- Used in packet sniffers and custom protocol implementation
- Requires root privileges on most OSes
Address Families
When creating a socket, you also define the address family, which tells the OS
which protocol family to use:
Address Family | Constant | Use Case |
---|---|---|
IPv4 | AF_INET | Standard for most TCP/IP programs |
IPv6 | AF_INET6 | Next-gen networking support |
Unix Domain | AF_UNIX | IPC on the same machine |
For internet applications, AF_INET is most common.
Socket Lifecycle: A Simplified View
Here’s a breakdown of how socket communication typically works:
🖥 Server Side:
- socket() → Create a socket
- bind() → Assign an IP address and port
- listen() → Start listening for clients
- accept() → Accept a client connection
- recv() / send() → Communicate
- close() → Close the socket
💻 Client Side:
- socket() → Create a socket
- connect() → Connect to the server
- send() / recv() → Communicate
- close() → Close the socket
These APIs are defined in the <sys/socket.h> and <netinet/in.h> headers (on Linux/UNIX systems).
Socket Identifiers
When you create a socket, the OS returns a file descriptor (an integer ≥ 0) that uniquely identifies that socket.
You use this descriptor in all subsequent socket operations.