C++
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Object-Oriented C++
-
Section 4: Memory Management
-
Section 5: Templates and Generic Programming
-
Section 6: The Standard Template Library
-
Section 7: Modern C++ Features
-
Section 8: Error Handling
-
Section 9: Multithreading
-
Section 10: Operator Overloading and Type Conversion
-
Section 11: Advanced Topics
-
Section 12: Tooling and Build Systems
-
Section 13: Design Patterns in C++
-
Section 14: Interfacing with C and Systems Programming
-
Section 15: Networking and IPC Basics
-
Section 16: Graphics and Game Programming Basics
-
Section 17: The Boost Libraries
-
Section 18: Data Structures and Algorithms in C++
-
Section 19: Practical Projects
-
Section 20: More Concurrency Patterns
-
Section 21: More OOP and Design Practice
-
Section 22: File I/O and Streams
-
Section 23: More Standard Library
-
Section 24: Practice Exercises
-
Section 25: Interview and Algorithm Practice
-
Section 26: Compiler and Language Internals
-
Section 27: GUI and Application Frameworks Overview
-
Section 28: Testing and Quality Practices
-
Section 29: Numerics Library
-
Section 30: Concepts Library (C++20)
-
Section 31: Ranges Library (C++20) In Depth
-
Section 32: More Utility Library
177: Building a Basic HTTP Client from Sockets
How do I actually "talk" HTTP over a raw socket?
The biggest secret about HTTP is that, at its core, it's just plain text sent over a TCP connection. You don't need a fancy library to start; you just need to send a string that follows the HTTP specification. If you're building a basic client, you're essentially just writing a formatted string to the socket using send().
For a basic GET request, you need the method (GET), the path (/), the version (HTTP/1.1), and a few mandatory headers. I usually recommend keeping it simple. Here is how I'd structure the request string in C++:
std::string request =
"GET / HTTP/1.1\r\n"
"Host: example.com\r\n"
"Connection: close\r\n"
"\r\n";
if (send(sock, request.c_str(), request.length(), 0) == -1) {
perror("send failed");
// handle error
}
Notice those \r\n sequences? That's Carriage Return and Line Feed. HTTP is very picky about this. If you just use \n, some servers will ignore you or throw a 400 Bad Request error. Also, that double \r\n at the end is critical—it tells the server, "I'm done sending headers, please process the request."
Why do I need that Host header? Isn't the IP address enough?
This trips up almost everyone the first time they do this. You'd think that since you connected your socket to a specific IP address, the server would know who you're looking for. But in the real world, one single IP address often hosts hundreds of different websites (this is called virtual hosting).
When the request hits the server, the web server software (like Apache or Nginx) looks at the Host header to decide which directory on the disk to serve you. If you omit Host: example.com\r\n, the server will likely return a 404 or a default page because it has no idea which specific site you're requesting from its pool of hosted domains.
How do I know when the server is finished sending the response?
Since sockets are stream-oriented, recv() doesn't magically know where an HTTP response ends. It just gives you whatever bytes have arrived in the buffer. You have two main choices here: you can either parse the Content-Length header to know exactly how many bytes to expect, or you can tell the server to close the connection as soon as it's done.
In the example above, I used Connection: close. This is the "easy mode" for beginners. It tells the server, "Once you've sent the data, hang up the phone." This means your recv() loop will eventually return 0, which is your signal that the transmission is complete. I've written a typical read loop for this below:
char buffer[4096];
std::string response;
int bytes_received;
while ((bytes_received = recv(sock, buffer, sizeof(buffer) - 1, 0)) > 0) {
buffer[bytes_received] = '\0'; // Null-terminate for safety
response += buffer;
}
if (bytes_received == -1) {
perror("recv failed");
}
Just a heads up: in a production environment, you'd avoid Connection: close and use keep-alive to reuse the socket for multiple requests, but that requires a much more complex parser to handle the Content-Length or Transfer-Encoding: chunked headers.
📋 Practical Task
Exercise: Building a Page-Length Counter for example.com
Your task is to create a C++ program that connects to example.com (IP: 93.184.216.34) on port 80 and retrieves the home page. Instead of printing the entire HTML body to the console, your program must calculate and print only the total number of bytes received in the response (including the headers).
- Use
socket(),connect(),send(), andrecv(). - Ensure you use the
Connection: closeheader to simplify your reading loop. - The final output should be a single line: "Total bytes received: [number]".
There are no comments for now.