TCP (Transmission Control Protocol) is one of the most reliable ways to communicate over a network. In this guide, we will walk through how to build a basic TCP server in C/C++ using socket programming.
What is a TCP Server?
A TCP server is a program that:
- Waits (listens) for incoming connections from clients.
- Accepts a connection request.
- Reads data sent by the client.
- Sends responses (optional)
- Closes the connection gracefully.
Required Headers
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h> // close()
#include <arpa/inet.h> // inet_ntoa(), htons(), etc.
#include <netinet/in.h> // sockaddr_in
#include <sys/socket.h> // socket(), bind(), listen(), accept()
Step-by-Step: Building a TCP Server
1️⃣ Create a Socket
int server_fd = socket(AF_INET, SOCK_STREAM, 0);
if (server_fd == -1) {
perror("Socket creation failed");
exit(EXIT_FAILURE);
}
- AF_INET – IPv4 address family
- SOCK_STREAM – TCP (as opposed to SOCK_DGRAM for UDP)
- 0 – default protocol (TCP in this case)
2️⃣ Set Up Server Address Structure
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(8080); // Port number (8080)
server_addr.sin_addr.s_addr = INADDR_ANY; // Bind to all interfaces
- htons() – converts port from host to network byte order
- INADDR_ANY – binds to all available network interfaces
3️⃣ Bind the Socket to the IP/Port
if (bind(server_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
perror("Bind failed");
exit(EXIT_FAILURE);
}
This reserves the specified port so the server can listen on it
4️⃣ Listen for incoming Connections
if (listen(server_fd, 5) < 0) {
perror("Listen failed");
exit(EXIT_FAILURE);
}
- The
5
is the backlog: how many connections can be queued before being accepted.
5️⃣ Accept Client Connections
struct sockaddr_in client_addr;
socklen_t addrlen = sizeof(client_addr);
int client_socket = accept(server_fd, (struct sockaddr *)&client_addr, &addrlen);
if (client_socket < 0) {
perror("Accept failed");
exit(EXIT_FAILURE);
}
printf("Connection accepted from %s:%d\n",
inet_ntoa(client_addr.sin_addr),
ntohs(client_addr.sin_port));
6️⃣ Communicate with the Client
char buffer[1024] = {0};
read(client_socket, buffer, sizeof(buffer));
printf("Client: %s\n", buffer);
char *response = "Hello from server!";
send(client_socket, response, strlen(response), 0);
7️⃣ Close Sockets
close(client_socket);
close(server_fd);
Full Working Code of the Server:
#include <stdio.h> // Standard I/O functions
#include <stdlib.h> // For exit()
#include <string.h> // For memset and string operations
#include <unistd.h> // For close()
#include <arpa/inet.h> // For inet_ntoa, htons, etc.
#include <netinet/in.h> // For sockaddr_in
#include <sys/socket.h> // For socket functions
int main() {
int server_fd, client_socket;
struct sockaddr_in server_addr, client_addr;
socklen_t addrlen = sizeof(client_addr);
char buffer[1024] = {0};
// 1. Create a TCP socket (IPv4, stream-based)
server_fd = socket(AF_INET, SOCK_STREAM, 0);
if (server_fd < 0) {
perror("Socket failed");
exit(EXIT_FAILURE);
}
// 2. Set server address structure
server_addr.sin_family = AF_INET; // IPv4
server_addr.sin_port = htons(8080); // Port 8080 (converted to network byte order)
server_addr.sin_addr.s_addr = INADDR_ANY; // Bind to any available interface (localhost or network)
// 3. Bind the socket to the specified IP and port
if (bind(server_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
perror("Bind failed");
exit(EXIT_FAILURE);
}
// 4. Listen for incoming connections (maximum 5 queued connections)
if (listen(server_fd, 5) < 0) {
perror("Listen failed");
exit(EXIT_FAILURE);
}
printf("Server is listening on port 8080...\n");
// 5. Accept a new client connection
client_socket = accept(server_fd, (struct sockaddr *)&client_addr, &addrlen);
if (client_socket < 0) {
perror("Accept failed");
exit(EXIT_FAILURE);
}
// 6. Print client's IP and port
printf("Connection accepted from %s:%d\n",
inet_ntoa(client_addr.sin_addr), // Convert client's IP to human-readable string
ntohs(client_addr.sin_port)); // Convert client's port to host byte order
// 7. Receive data from the client
read(client_socket, buffer, sizeof(buffer));
printf("Client says: %s\n", buffer);
// 8. Send a response to the client
char *msg = "Hello from server!";
send(client_socket, msg, strlen(msg), 0);
// 9. Close both client and server sockets
close(client_socket);
close(server_fd);
return 0;
}
This code sets up a simple TCP server that listens on port 8080, accepts one client connection, receives a message, sends a response, and then exits.
What is a TCP Client?
A TCP client is a program that:
- Creates a socket.
- Connects to a server's IP address and port.
- Sends a request or data.
- Receives a response from the server.
- Closes the connection.
Step-by-Step: Writing a TCP Client
Required Headers
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h> // close()
#include <arpa/inet.h> // inet_pton(), sockaddr_in
#include <netinet/in.h> // struct sockaddr_in
#include <sys/socket.h> // socket(), connect()
1️⃣ Create a Socket
int sock_fd = socket(AF_INET, SOCK_STREAM, 0);
if (sock_fd < 0) {
perror("Socket creation failed");
exit(EXIT_FAILURE);
}
Same as the server – we use AF_INET
and SOCK_STREAM
.
2️⃣ Setup Server Address Structure
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(8080);
inet_pton(AF_INET, "127.0.0.1", &server_addr.sin_addr); // Convert IP to binary form
- inet_pton() – converts a human-readable IP to network format.
3️⃣ Connect to Server
if (connect(sock_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
perror("Connection failed");
exit(EXIT_FAILURE);
}
- The TCP client initiates the connection to the server.
4️⃣ Send a Message to the Server
char *msg = "Hello from client!";
send(sock_fd, msg, strlen(msg), 0);
5️⃣ Receives Response
char buffer[1024] = {0};
read(sock_fd, buffer, sizeof(buffer));
printf("Server replied: %s\n", buffer);
6️⃣ Close the Connection
close(sock_fd);
Full Working Client Code:
#include <stdio.h> // Standard I/O functions
#include <stdlib.h> // For exit()
#include <string.h> // For memset and string operations
#include <unistd.h> // For close(), read(), write()
#include <arpa/inet.h> // For inet_pton(), htons(), etc.
#include <netinet/in.h> // For sockaddr_in
#include <sys/socket.h> // For socket functions
int main() {
int sock_fd;
struct sockaddr_in server_addr;
char buffer[1024] = {0}; // Buffer to store incoming message from server
// 1. Create a socket (IPv4, TCP)
sock_fd = socket(AF_INET, SOCK_STREAM, 0);
if (sock_fd < 0) {
perror("Socket creation failed");
exit(EXIT_FAILURE);
}
// 2. Set up the server address structure
server_addr.sin_family = AF_INET; // IPv4
server_addr.sin_port = htons(8080); // Port 8080 (host to network byte order)
// 3. Convert and set the IP address (127.0.0.1 => localhost)
if (inet_pton(AF_INET, "127.0.0.1", &server_addr.sin_addr) <= 0) {
perror("Invalid address / Address not supported");
exit(EXIT_FAILURE);
}
// 4. Connect to the server
if (connect(sock_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
perror("Connection Failed");
exit(EXIT_FAILURE);
}
// 5. Send a message to the server
char *msg = "Hello from client!";
send(sock_fd, msg, strlen(msg), 0);
printf("Message sent to server.\n");
// 6. Read response from server
read(sock_fd, buffer, sizeof(buffer));
printf("Server response: %s\n", buffer);
// 7. Close the socket
close(sock_fd);
return 0;
}
This client program:
- Connects to a server running on
127.0.0.1:8080
- Sends a greeting message
- Waits for the response from the server
- Prints the server's response and closes the connection