TCP/IP Socket Programming Guide
TCP/IP socket programming is the foundation of networked applications—web servers, databases, chat apps, games, and more. This blog walks you through what sockets are, how TCP/IP fits in, and how to write a simple client–server program in C/C++, explaining the key structures and system calls along the way.
1. What Is a Socket?
A socket is an endpoint for communication between two machines (or processes) over a network.
Think of it like:
- IP address → identifies the machine
- Port number → identifies the application
- Socket → (IP address + port + protocol)
Sockets allow programs to:
- Send data
- Receive data
- Manage connections
2. TCP/IP in a Nutshell
TCP/IP is a protocol suite with layers:
| Layer | Responsibility |
|---|---|
| Application | HTTP, FTP, SMTP |
| Transport | TCP, UDP |
| Internet | IP |
| Link | Ethernet, Wi-Fi |
In socket programming:
- TCP sockets → reliable, connection-oriented
- UDP sockets → fast, connectionless
This blog focuses on TCP sockets.
3. Client–Server Model
TCP Server Flow
- Create a socket
- Bind it to an IP + port
- Listen for connections
- Accept a client
- Send/receive data
- Close connection
TCP Client Flow
- Create a socket
- Connect to server
- Send/receive data
- Close socket
4. Key Data Structures
struct sockaddr
Generic socket address structure.
struct sockaddr {
sa_family_t sa_family;
char sa_data[14];
};Usually not used directly.
struct sockaddr_in (IPv4)
struct sockaddr_in {
sa_family_t sin_family; // AF_INET
in_port_t sin_port; // Port number
struct in_addr sin_addr; // IP address
};Example:
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(8080);
server_addr.sin_addr.s_addr = INADDR_ANY;htons()→ host to network byte order (short)
INADDR_ANY→ bind to all local interfaces
struct addrinfo (Modern & Flexible)
Used with getaddrinfo() for protocol-independent code.
struct addrinfo hints, *res;
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_INET; // IPv4
hints.ai_socktype = SOCK_STREAM; // TCP5. Important Socket Functions
1. socket()
Creates a socket.
int sockfd = socket(AF_INET, SOCK_STREAM, 0);AF_INET→ IPv4
SOCK_STREAM→ TCP
2. bind()
Associates socket with IP + port (server-side).
bind(sockfd,
(struct sockaddr *)&server_addr,
sizeof(server_addr));3. listen()
Marks socket as passive (waiting for connections).
listen(sockfd, 5);5→ backlog (pending connections)
4. accept()
Accepts an incoming connection.
int client_fd;
struct sockaddr_in client_addr;
socklen_t addr_len = sizeof(client_addr);
client_fd = accept(sockfd,
(struct sockaddr *)&client_addr,
&addr_len);Returns new socket descriptor for the client.
5. connect()
Client connects to server.
connect(sockfd,
(struct sockaddr *)&server_addr,
sizeof(server_addr));6. send() / recv()
send(client_fd, buffer, strlen(buffer), 0);
recv(client_fd, buffer, sizeof(buffer), 0);6. Simple TCP Server (C)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
int main() {
int server_fd, client_fd;
struct sockaddr_in server_addr, client_addr;
socklen_t addr_len = sizeof(client_addr);
char buffer[1024] = {0};
server_fd = socket(AF_INET, SOCK_STREAM, 0);
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(8080);
server_addr.sin_addr.s_addr = INADDR_ANY;
bind(server_fd,
(struct sockaddr *)&server_addr,
sizeof(server_addr));
listen(server_fd, 5);
printf("Server listening on port 8080...\n");
client_fd = accept(server_fd,
(struct sockaddr *)&client_addr,
&addr_len);
recv(client_fd, buffer, sizeof(buffer), 0);
printf("Client says: %s\n", buffer);
send(client_fd, "Hello from server", 17, 0);
close(client_fd);
close(server_fd);
return 0;
}7. Simple TCP Client (C++)
#include <iostream>
#include <cstring>
#include <unistd.h>
#include <arpa/inet.h>
int main() {
int sockfd;
struct sockaddr_in server_addr;
char buffer[1024] = {0};
sockfd = socket(AF_INET, SOCK_STREAM, 0);
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(8080);
inet_pton(AF_INET, "127.0.0.1", &server_addr.sin_addr);
connect(sockfd,
(struct sockaddr *)&server_addr,
sizeof(server_addr));
send(sockfd, "Hello from client", 17, 0);
recv(sockfd, buffer, sizeof(buffer), 0);
std::cout << "Server replied: " << buffer << std::endl;
close(sockfd);
return 0;
}8. Common Pitfalls
- Forgetting
htons()/htonl()
- Not checking return values
- Using blocking sockets unintentionally
- Not closing sockets (resource leaks)
- Hardcoding IPv4 instead of
getaddrinfo()
9. Why Use getaddrinfo()?
Modern, portable, and supports:
- IPv4 & IPv6
- Cleaner error handling
- DNS resolution
Recommended for production code.
10. Final Thoughts
TCP/IP socket programming may feel low-level, but it gives you:
- Full control over networking
- Deeper understanding of how the internet works
- Strong foundation for higher-level frameworks
Once comfortable with these basics, moving to libraries like Boost.Asio, libuv, or frameworks like gRPC becomes much easier.