🔌 Part 1: Building a Simple TCP Client in C
As engineers, we often work several layers above the network stack—abstracted by frameworks, SDKs, and libraries. Recently, I decided to go back to basics and explore socket programming in C by building a simple TCP client from scratch.
The goal? Connect to a server send a raw HTTP request, and read the response—all using low-level system calls.
🧠 What I Learned (Client Side)
Creating a socket
- Used socket(AF_INET, SOCK_STREAM, 0) to create a TCP socket with IPv4.
Preparing the server address
- inet_addr() to convert IP string to binary
- htons() to convert port to network byte order
Connecting to the server
- Used connect() with a typecast to struct sockaddr*
- Passed in a sockaddr_in struct with Server’s IP and port 80
Sending and receiving data
- Used write() to send an HTTP GET request
- Used read() to fetch the response from the server
Man pages were essential
- Especially man 2 socket, man 2 connect, man 2 read, etc.
🧪 Sample Code
/* tcp_client.c */
#include
#include
#include
#include
#include
#include
#define IP "142.250.70.100"
#define PORT 80
int main()
{
int s;
struct sockaddr_in sserver;
char* data;
char buf[10240];
data = "GET /webhp HTTP/1.0\n\n";
s = socket(AF_INET, SOCK_STREAM, 0);
if(s < 0)
{
printf("socket()\n");
return -1;
}
sserver.sin_addr.s_addr = inet_addr(IP);
sserver.sin_port = htons(PORT);
sserver.sin_family = AF_INET;
if(connect(s, (struct sockaddr*)&sserver, sizeof(sserver)) != 0)
{
printf("connect()\n");
close(s);
return -1;
}
write(s, data, strlen(data));
read(s, buf, 10239);
close(s);
printf("\n%s\n", buf);
return 0;
}
🖥️ Part 2: Writing a Simple TCP Server in C
In Part 1 (link to Part 1), I shared how I built a simple TCP client in C to connect to a server, send an HTTP request, and read the response. This time, I flipped the role—writing a TCP server from scratch that listens on port 8181, accepts client connections, and responds with a minimal HTTP reply.
🔄 What the Server Does
This TCP server:
- Listens on 0.0.0.0:8181
- Accepts incoming TCP connections
- Reads the client’s request
- Responds with a static HTTP response (hello)
- Sleeps for 2 minutes (120s) before replying—to simulate a long-running process
🧠 What I Learned (Server Side)
Creating and binding a server socket
- Used socket(AF_INET, SOCK_STREAM, 0) to create a TCP socket
- Used a sockaddr_in struct to bind the server to port 8181 on all interfaces using bind()
Listening for incoming connections
- Called listen(s, 1) to queue one pending connection
- Interestingly, the backlog queue didn’t behave as expected—still exploring why that might be OS or implementation dependent
Accepting clients using accept()
- Accepts a new connection and returns a client socket descriptor
- accept() also fills in the client’s socket address.
Simple client-server interaction
- Read the incoming request using read()
- Delayed for 2 minutes to simulate latency
- Replied with a static HTTP/1.1 200 OK response using write()
🧪 Sample Code
/* tcp_server.c */
#include
#include
#include
#include
#include
#define PORT 8181
int main()
{
int c, s;
struct sockaddr_in cli, srv;
char buf[1024];
char* data;
socklen_t addrlen;
addrlen = 0;
data = "HTTP/1.1 200 OK\nContent-Type: text/html\nContent-Length: 5\n\nhello";
memset(&cli, 0, sizeof(cli));
memset(&srv, 0, sizeof(srv));
s = socket(AF_INET, SOCK_STREAM, 0);
if(s == -1)
{
printf("socket()\n");
return -1;
}
srv.sin_family = AF_INET;
srv.sin_port = htons(PORT);
srv.sin_addr.s_addr = 0;
if(bind(s, (struct sockaddr*)&srv, sizeof(srv)))
{
printf("bind()\n");
close(s);
return -1;
}
if(listen(s, 1))
{
printf("listen()\n");
close(s);
return -1;
}
printf("Listening on 0.0.0.0:%d\n", PORT);
while(1)
{
addrlen = 0;
c = accept(s, (struct sockaddr *)&cli, &addrlen);
if(c == -1)
{
printf("accept()\n");
close(s);
return -1;
}
printf("client connected\n");
read(c, buf, 1023);
sleep(120);
write(c, data, strlen(data));
close(c);
}
close(s);
return 0;
}
Thanks to Jonas Birch for his excellent instructional videos. His ability to explain system-level concepts clearly was a huge help during this learning phase.