In this article, you’ll create a Full-Duplex TCP Echo Server and Client. This means the client and server can send and receive data independently and simultaneously—just like in real-world chat systems.
🎯 Objective
Build a server that:
- Accepts multiple messages from the client.
- Echoes each message back.
And a client that:
- Sends multiple messages to the server.
- Receives the echo responses.
- Can send and receive concurrently (optional enhancement).
⚙️ Part 1: Echo Server (Single-Client, Full-Duplex)
Step-by-Step Breakdown
- Create the socket
- Bind to IP and port
- Listen and accept a connection
- Enter a loop:
- Read from client
- Print and echo back
- Break if client sends "exit"
Full Code: echo_server.c
#include <stdio.h> // For printf(), perror()
#include <stdlib.h> // For exit()
#include <string.h> // For memset(), strncmp(), strlen()
#include <unistd.h> // For close(), read(), write()
#include <arpa/inet.h> // For inet_ntoa(), htons(), etc.
#include <netinet/in.h> // For sockaddr_in structure
#include <sys/socket.h> // For socket system calls
int main() {
int server_fd, client_fd;
struct sockaddr_in server_addr, client_addr;
socklen_t addrlen = sizeof(client_addr);
char buffer[1024];
// 1. Create TCP socket (IPv4)
server_fd = socket(AF_INET, SOCK_STREAM, 0);
if (server_fd < 0) {
perror("socket");
exit(EXIT_FAILURE);
}
// 2. Configure server address structure
server_addr.sin_family = AF_INET; // IPv4
server_addr.sin_port = htons(8080); // Port 8080 (network byte order)
server_addr.sin_addr.s_addr = INADDR_ANY; // Listen on all available interfaces
// 3. Bind the socket to the address and port
bind(server_fd, (struct sockaddr*)&server_addr, sizeof(server_addr));
// 4. Start listening for incoming connections (max 5 in queue)
listen(server_fd, 5);
printf("Server listening on port 8080...\n");
// 5. Accept a client connection
client_fd = accept(server_fd, (struct sockaddr*)&client_addr, &addrlen);
printf("Client connected: %s:%d\n",
inet_ntoa(client_addr.sin_addr), // Convert IP to readable format
ntohs(client_addr.sin_port)); // Convert port to host byte order
// 6. Communication loop
while (1) {
memset(buffer, 0, sizeof(buffer)); // Clear buffer before each read
int bytes = read(client_fd, buffer, sizeof(buffer)); // Read from client
if (bytes <= 0) break; // Exit loop on error or disconnect
printf("Client: %s", buffer); // Print client message
if (strncmp(buffer, "exit", 4) == 0) break; // If message starts with "exit", break
send(client_fd, buffer, strlen(buffer), 0); // Echo message back to client
}
// 7. Close client and server sockets
close(client_fd);
close(server_fd);
printf("Connection closed.\n");
return 0;
}
What this program does:
- Listens on TCP port 8080.
- Accepts a single client.
- Echoes back any message received.
- Terminates when it receives "exit" from the client.
⚙️ Part 2: Echo Client (Interactive)
Full Code: echo_client.c
#include <stdio.h> // For printf(), fgets(), etc.
#include <stdlib.h> // For exit()
#include <string.h> // For memset(), strlen(), strncmp()
#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 system calls
int main() {
int sock_fd;
struct sockaddr_in server_addr;
char buffer[1024]; // Buffer for sending and receiving data
// 1. Create TCP socket
sock_fd = socket(AF_INET, SOCK_STREAM, 0);
// 2. Setup server address
server_addr.sin_family = AF_INET; // IPv4
server_addr.sin_port = htons(8080); // Port 8080 in network byte order
inet_pton(AF_INET, "127.0.0.1", &server_addr.sin_addr); // Convert IP to binary format
// 3. Connect to the server
connect(sock_fd, (struct sockaddr*)&server_addr, sizeof(server_addr));
printf("Connected to server. Type messages (type 'exit' to quit):\n");
// 4. Communication loop
while (1) {
memset(buffer, 0, sizeof(buffer)); // Clear the buffer before input
fgets(buffer, sizeof(buffer), stdin); // Get user input (includes newline)
send(sock_fd, buffer, strlen(buffer), 0); // Send message to server
if (strncmp(buffer, "exit", 4) == 0) break; // If input starts with "exit", exit loop
memset(buffer, 0, sizeof(buffer)); // Clear buffer for server response
read(sock_fd, buffer, sizeof(buffer)); // Read server response
printf("Server: %s", buffer); // Print server response
}
// 5. Close the socket
close(sock_fd);
return 0;
}
What it does:
- Connects to a TCP server at 127.0.0.1:8080
- Accepts user input using fgets()
- Sends input to the server and prints the response
- Quits the loop when the input starts with "exit"
Demo
1 Compile both programs:
gcc echo_server.c -o server
gcc echo_client.c -o client
2 Run server in one terminal:
./server
3 Run client in another
./client