🎯 Exemples recommandés
Balanced sample collections from various categories for you to explore
Programmation Réseau Windows - Exemples C++
Exemples complets de programmation réseau en C++ pour plateforme Windows incluant requêtes HTTP, sockets TCP et implémentation serveur HTTP
💻 Requêtes HTTP GET/POST cpp
🟡 intermediate
⭐⭐⭐
Envoyer requêtes HTTP GET et POST utilisant API WinINet avec gestion d'erreurs et analyse de réponses
⏱️ 20 min
🏷️ cpp, networking, http, windows
Prerequisites:
WinINet API, HTTP protocol, Windows networking
#include <iostream>
#include <string>
#include <vector>
#include <windows.h>
#include <wininet.h>
#include <sstream>
#include <map>
#pragma comment(lib, "wininet.lib")
// HTTP Response structure
struct HttpResponse {
std::string statusCode;
std::string statusText;
std::map<std::string, std::string> headers;
std::string body;
bool success;
HttpResponse() : success(false) {}
};
// 1. Basic HTTP GET request
HttpResponse HttpGet(const std::string& url, const std::map<std::string, std::string>& headers = {}) {
std::cout << "=== HTTP GET Request ===" << std::endl;
std::cout << "URL: " << url << std::endl;
HttpResponse response;
try {
// Parse URL components
DWORD serviceType;
std::string serverName, objectName;
INTERNET_PORT port;
char buffer[1024];
DWORD bufferSize = sizeof(buffer);
if (!InternetCrackUrlA(url.c_str(), 0, 0, nullptr)) {
DWORD error = GetLastError();
response.statusText = "Failed to parse URL. Error: " + std::to_string(error);
std::cout << response.statusText << std::endl;
return response;
}
URL_COMPONENTSA urlComponents = {0};
urlComponents.dwStructSize = sizeof(urlComponents);
urlComponents.lpszHostName = buffer;
urlComponents.dwHostNameLength = bufferSize;
urlComponents.lpszUrlPath = buffer + bufferSize/2;
urlComponents.dwUrlPathLength = bufferSize/2;
if (!InternetCrackUrlA(url.c_str(), 0, 0, &urlComponents)) {
response.statusText = "Failed to parse URL components";
return response;
}
serverName = std::string(urlComponents.lpszHostName, urlComponents.dwHostNameLength);
objectName = std::string(urlComponents.lpszUrlPath, urlComponents.dwUrlPathLength);
serviceType = urlComponents.nScheme;
port = urlComponents.nPort;
if (port == 0) {
port = (serviceType == INTERNET_SCHEME_HTTPS) ? 443 : 80;
}
std::cout << "Server: " << serverName << ", Port: " << port << std::endl;
std::cout << "Object: " << objectName << std::endl;
// Initialize WinINet
HINTERNET hInternet = InternetOpenA(
"C++ HTTP Client/1.0",
INTERNET_OPEN_TYPE_DIRECT,
NULL,
NULL,
0
);
if (!hInternet) {
response.statusText = "Failed to initialize WinINet";
return response;
}
// Connect to server
HINTERNET hConnect = InternetConnectA(
hInternet,
serverName.c_str(),
port,
NULL,
NULL,
INTERNET_SERVICE_HTTP,
0,
0
);
if (!hConnect) {
DWORD error = GetLastError();
response.statusText = "Failed to connect to server. Error: " + std::to_string(error);
InternetCloseHandle(hInternet);
return response;
}
// Create HTTP request
DWORD flags = (serviceType == INTERNET_SCHEME_HTTPS) ? INTERNET_FLAG_SECURE : 0;
flags |= INTERNET_FLAG_RELOAD | INTERNET_FLAG_NO_CACHE_WRITE;
HINTERNET hRequest = HttpOpenRequestA(
hConnect,
"GET",
objectName.c_str(),
HTTP_VERSIONA,
NULL,
NULL,
flags,
0
);
if (!hRequest) {
response.statusText = "Failed to create HTTP request";
InternetCloseHandle(hConnect);
InternetCloseHandle(hInternet);
return response;
}
// Add custom headers
for (const auto& header : headers) {
std::string headerLine = header.first + ": " + header.second;
HttpAddRequestHeadersA(hRequest, headerLine.c_str(), -1, HTTP_ADDREQ_FLAG_ADD);
}
// Send request
if (!HttpSendRequestA(hRequest, NULL, 0, NULL, 0)) {
DWORD error = GetLastError();
response.statusText = "Failed to send HTTP request. Error: " + std::to_string(error);
InternetCloseHandle(hRequest);
InternetCloseHandle(hConnect);
InternetCloseHandle(hInternet);
return response;
}
// Get status code
DWORD statusCode = 0;
DWORD statusCodeSize = sizeof(statusCode);
HttpQueryInfoA(hRequest, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER,
&statusCode, &statusCodeSize, NULL);
response.statusCode = std::to_string(statusCode);
// Get status text
char statusText[256] = {0};
DWORD statusTextSize = sizeof(statusText);
HttpQueryInfoA(hRequest, HTTP_QUERY_STATUS_TEXT,
statusText, &statusTextSize, NULL);
response.statusText = statusText;
std::cout << "Status: " << statusCode << " " << statusText << std::endl;
// Get response headers
char headersBuffer[4096] = {0};
DWORD headersSize = sizeof(headersBuffer);
HttpQueryInfoA(hRequest, HTTP_QUERY_RAW_HEADERS_CRLF,
headersBuffer, &headersSize, NULL);
std::istringstream headersStream(headersBuffer);
std::string headerLine;
while (std::getline(headersStream, headerLine)) {
size_t colonPos = headerLine.find(':');
if (colonPos != std::string::npos) {
std::string key = headerLine.substr(0, colonPos);
std::string value = headerLine.substr(colonPos + 1);
// Trim whitespace
key.erase(0, key.find_first_not_of(" \t"));
key.erase(key.find_last_not_of(" \t") + 1);
value.erase(0, value.find_first_not_of(" \t"));
value.erase(value.find_last_not_of(" \t") + 1);
response.headers[key] = value;
}
}
// Read response body
DWORD bytesRead;
char bodyBuffer[8192];
std::string responseBody;
while (InternetReadFile(hRequest, bodyBuffer, sizeof(bodyBuffer) - 1, &bytesRead) && bytesRead > 0) {
bodyBuffer[bytesRead] = '\0';
responseBody += bodyBuffer;
}
response.body = responseBody;
response.success = (statusCode >= 200 && statusCode < 300);
std::cout << "Response headers received: " << response.headers.size() << std::endl;
std::cout << "Response body size: " << responseBody.length() << " bytes" << std::endl;
// Cleanup
InternetCloseHandle(hRequest);
InternetCloseHandle(hConnect);
InternetCloseHandle(hInternet);
} catch (const std::exception& e) {
response.statusText = "Exception occurred: " + std::string(e.what());
std::cout << response.statusText << std::endl;
}
return response;
}
// 2. HTTP POST request with JSON data
HttpResponse HttpPost(const std::string& url, const std::string& postData,
const std::map<std::string, std::string>& headers = {}) {
std::cout << "\n=== HTTP POST Request ===" << std::endl;
std::cout << "URL: " << url << std::endl;
std::cout << "Data size: " << postData.length() << " bytes" << std::endl;
HttpResponse response;
try {
// Parse URL (reuse code from GET)
DWORD serviceType;
std::string serverName, objectName;
INTERNET_PORT port = 80;
URL_COMPONENTSA urlComponents = {0};
urlComponents.dwStructSize = sizeof(urlComponents);
char hostBuffer[512], pathBuffer[1024];
urlComponents.lpszHostName = hostBuffer;
urlComponents.dwHostNameLength = sizeof(hostBuffer);
urlComponents.lpszUrlPath = pathBuffer;
urlComponents.dwUrlPathLength = sizeof(pathBuffer);
if (!InternetCrackUrlA(url.c_str(), 0, 0, &urlComponents)) {
response.statusText = "Failed to parse URL";
return response;
}
serverName = std::string(urlComponents.lpszHostName, urlComponents.dwHostNameLength);
objectName = std::string(urlComponents.lpszUrlPath, urlComponents.dwUrlPathLength);
serviceType = urlComponents.nScheme;
port = (urlComponents.nPort == 0) ?
((serviceType == INTERNET_SCHEME_HTTPS) ? 443 : 80) : urlComponents.nPort;
// Initialize WinINet
HINTERNET hInternet = InternetOpenA(
"C++ HTTP Client/1.0",
INTERNET_OPEN_TYPE_DIRECT,
NULL,
NULL,
0
);
if (!hInternet) {
response.statusText = "Failed to initialize WinINet";
return response;
}
// Connect to server
HINTERNET hConnect = InternetConnectA(
hInternet,
serverName.c_str(),
port,
NULL,
NULL,
INTERNET_SERVICE_HTTP,
0,
0
);
if (!hConnect) {
response.statusText = "Failed to connect to server";
InternetCloseHandle(hInternet);
return response;
}
// Create HTTP request
DWORD flags = (serviceType == INTERNET_SCHEME_HTTPS) ? INTERNET_FLAG_SECURE : 0;
flags |= INTERNET_FLAG_RELOAD | INTERNET_FLAG_NO_CACHE_WRITE;
HINTERNET hRequest = HttpOpenRequestA(
hConnect,
"POST",
objectName.c_str(),
HTTP_VERSIONA,
NULL,
NULL,
flags,
0
);
if (!hRequest) {
response.statusText = "Failed to create HTTP request";
InternetCloseHandle(hConnect);
InternetCloseHandle(hInternet);
return response;
}
// Add headers
std::string contentTypeHeader = "Content-Type: application/json";
HttpAddRequestHeadersA(hRequest, contentTypeHeader.c_str(), -1, HTTP_ADDREQ_FLAG_ADD);
std::string contentLengthHeader = "Content-Length: " + std::to_string(postData.length());
HttpAddRequestHeadersA(hRequest, contentLengthHeader.c_str(), -1, HTTP_ADDREQ_FLAG_ADD);
for (const auto& header : headers) {
std::string headerLine = header.first + ": " + header.second;
HttpAddRequestHeadersA(hRequest, headerLine.c_str(), -1, HTTP_ADDREQ_FLAG_ADD);
}
// Send POST request
if (!HttpSendRequestA(hRequest, NULL, 0, (LPVOID)postData.c_str(), postData.length())) {
DWORD error = GetLastError();
response.statusText = "Failed to send POST request. Error: " + std::to_string(error);
InternetCloseHandle(hRequest);
InternetCloseHandle(hConnect);
InternetCloseHandle(hInternet);
return response;
}
// Get response (reuse code from GET)
DWORD statusCode = 0;
DWORD statusCodeSize = sizeof(statusCode);
HttpQueryInfoA(hRequest, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER,
&statusCode, &statusCodeSize, NULL);
response.statusCode = std::to_string(statusCode);
char statusText[256] = {0};
DWORD statusTextSize = sizeof(statusText);
HttpQueryInfoA(hRequest, HTTP_QUERY_STATUS_TEXT,
statusText, &statusTextSize, NULL);
response.statusText = statusText;
std::cout << "Status: " << statusCode << " " << statusText << std::endl;
// Get headers and body (same as GET)
char headersBuffer[4096] = {0};
DWORD headersSize = sizeof(headersBuffer);
HttpQueryInfoA(hRequest, HTTP_QUERY_RAW_HEADERS_CRLF,
headersBuffer, &headersSize, NULL);
std::istringstream headersStream(headersBuffer);
std::string headerLine;
while (std::getline(headersStream, headerLine)) {
size_t colonPos = headerLine.find(':');
if (colonPos != std::string::npos) {
std::string key = headerLine.substr(0, colonPos);
std::string value = headerLine.substr(colonPos + 1);
key.erase(0, key.find_first_not_of(" \t"));
key.erase(key.find_last_not_of(" \t") + 1);
value.erase(0, value.find_first_not_of(" \t"));
value.erase(value.find_last_not_of(" \t") + 1);
response.headers[key] = value;
}
}
// Read response body
DWORD bytesRead;
char bodyBuffer[8192];
std::string responseBody;
while (InternetReadFile(hRequest, bodyBuffer, sizeof(bodyBuffer) - 1, &bytesRead) && bytesRead > 0) {
bodyBuffer[bytesRead] = '\0';
responseBody += bodyBuffer;
}
response.body = responseBody;
response.success = (statusCode >= 200 && statusCode < 300);
std::cout << "Response received successfully" << std::endl;
// Cleanup
InternetCloseHandle(hRequest);
InternetCloseHandle(hConnect);
InternetCloseHandle(hInternet);
} catch (const std::exception& e) {
response.statusText = "Exception occurred: " + std::string(e.what());
std::cout << response.statusText << std::endl;
}
return response;
}
// 3. Download file from URL
bool DownloadFile(const std::string& url, const std::string& filePath) {
std::cout << "\n=== File Download ===" << std::endl;
std::cout << "URL: " << url << std::endl;
std::cout << "Save to: " << filePath << std::endl;
try {
// Parse URL
URL_COMPONENTSA urlComponents = {0};
urlComponents.dwStructSize = sizeof(urlComponents);
char hostBuffer[512], pathBuffer[1024];
urlComponents.lpszHostName = hostBuffer;
urlComponents.dwHostNameLength = sizeof(hostBuffer);
urlComponents.lpszUrlPath = pathBuffer;
urlComponents.dwUrlPathLength = sizeof(pathBuffer);
if (!InternetCrackUrlA(url.c_str(), 0, 0, &urlComponents)) {
std::cout << "Failed to parse URL" << std::endl;
return false;
}
std::string serverName(hostBuffer, urlComponents.dwHostNameLength);
std::string objectName(pathBuffer, urlComponents.dwUrlPathLength);
INTERNET_PORT port = (urlComponents.nPort == 0) ?
((urlComponents.nScheme == INTERNET_SCHEME_HTTPS) ? 443 : 80) : urlComponents.nPort;
// Initialize WinINet
HINTERNET hInternet = InternetOpenA(
"C++ File Downloader/1.0",
INTERNET_OPEN_TYPE_DIRECT,
NULL,
NULL,
0
);
if (!hInternet) {
std::cout << "Failed to initialize WinINet" << std::endl;
return false;
}
// Connect and open URL
HINTERNET hUrl = InternetOpenUrlA(
hInternet,
url.c_str(),
NULL,
0,
INTERNET_FLAG_RELOAD | INTERNET_FLAG_NO_CACHE_WRITE |
((urlComponents.nScheme == INTERNET_SCHEME_HTTPS) ? INTERNET_FLAG_SECURE : 0),
0
);
if (!hUrl) {
DWORD error = GetLastError();
std::cout << "Failed to open URL. Error: " << error << std::endl;
InternetCloseHandle(hInternet);
return false;
}
// Get file size
DWORD fileSize = 0;
DWORD fileSizeSize = sizeof(fileSize);
HttpQueryInfoA(hUrl, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER,
&fileSize, &fileSizeSize, NULL);
if (fileSize > 0) {
std::cout << "File size: " << fileSize << " bytes" << std::endl;
}
// Create file
HANDLE hFile = CreateFileA(
filePath.c_str(),
GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL
);
if (hFile == INVALID_HANDLE_VALUE) {
std::cout << "Failed to create file" << std::endl;
InternetCloseHandle(hUrl);
InternetCloseHandle(hInternet);
return false;
}
// Download file
DWORD bytesRead;
DWORD totalBytes = 0;
char buffer[8192];
DWORD startTime = GetTickCount();
std::cout << "Downloading..." << std::endl;
while (InternetReadFile(hUrl, buffer, sizeof(buffer), &bytesRead) && bytesRead > 0) {
DWORD bytesWritten;
if (!WriteFile(hFile, buffer, bytesRead, &bytesWritten, NULL) || bytesWritten != bytesRead) {
std::cout << "Failed to write to file" << std::endl;
CloseHandle(hFile);
InternetCloseHandle(hUrl);
InternetCloseHandle(hInternet);
return false;
}
totalBytes += bytesRead;
// Show progress every 1MB
if (totalBytes % (1024 * 1024) == 0 || bytesRead < sizeof(buffer)) {
DWORD elapsed = GetTickCount() - startTime;
double speed = totalBytes / (elapsed / 1000.0) / 1024.0; // KB/s
std::cout << "Downloaded: " << totalBytes << " bytes";
if (fileSize > 0) {
double progress = (double)totalBytes / fileSize * 100.0;
std::cout << " (" << progress << "% complete)";
}
std::cout << ", Speed: " << speed << " KB/s" << std::endl;
}
}
DWORD elapsed = GetTickCount() - startTime;
double avgSpeed = totalBytes / (elapsed / 1000.0) / 1024.0;
std::cout << "Download completed!" << std::endl;
std::cout << "Total bytes: " << totalBytes << std::endl;
std::cout << "Average speed: " << avgSpeed << " KB/s" << std::endl;
std::cout << "Time taken: " << elapsed / 1000.0 << " seconds" << std::endl;
// Cleanup
CloseHandle(hFile);
InternetCloseHandle(hUrl);
InternetCloseHandle(hInternet);
return true;
} catch (const std::exception& e) {
std::cout << "Exception during download: " << e.what() << std::endl;
return false;
}
}
// 4. HTTP request with timeout
HttpResponse HttpGetWithTimeout(const std::string& url, int timeoutSeconds = 30) {
std::cout << "\n=== HTTP GET with Timeout ===" << std::endl;
std::cout << "URL: " << url << std::endl;
std::cout << "Timeout: " << timeoutSeconds << " seconds" << std::endl;
HttpResponse response;
try {
// Parse URL
URL_COMPONENTSA urlComponents = {0};
urlComponents.dwStructSize = sizeof(urlComponents);
char hostBuffer[512], pathBuffer[1024];
urlComponents.lpszHostName = hostBuffer;
urlComponents.dwHostNameLength = sizeof(hostBuffer);
urlComponents.lpszUrlPath = pathBuffer;
urlComponents.dwUrlPathLength = sizeof(pathBuffer);
if (!InternetCrackUrlA(url.c_str(), 0, 0, &urlComponents)) {
response.statusText = "Failed to parse URL";
return response;
}
std::string serverName(hostBuffer, urlComponents.dwHostNameLength);
std::string objectName(pathBuffer, urlComponents.dwUrlPathLength);
INTERNET_PORT port = (urlComponents.nPort == 0) ?
((urlComponents.nScheme == INTERNET_SCHEME_HTTPS) ? 443 : 80) : urlComponents.nPort;
// Initialize WinINet with timeout settings
HINTERNET hInternet = InternetOpenA(
"C++ HTTP Client/1.0",
INTERNET_OPEN_TYPE_DIRECT,
NULL,
NULL,
0
);
if (!hInternet) {
response.statusText = "Failed to initialize WinINet";
return response;
}
// Set timeouts
DWORD timeoutMs = timeoutSeconds * 1000;
InternetSetOptionA(hInternet, INTERNET_OPTION_CONNECT_TIMEOUT, &timeoutMs, sizeof(timeoutMs));
InternetSetOptionA(hInternet, INTERNET_OPTION_SEND_TIMEOUT, &timeoutMs, sizeof(timeoutMs));
InternetSetOptionA(hInternet, INTERNET_OPTION_RECEIVE_TIMEOUT, &timeoutMs, sizeof(timeoutMs));
// Connect to server
HINTERNET hConnect = InternetConnectA(
hInternet,
serverName.c_str(),
port,
NULL,
NULL,
INTERNET_SERVICE_HTTP,
0,
0
);
if (!hConnect) {
DWORD error = GetLastError();
response.statusText = "Connection failed or timeout. Error: " + std::to_string(error);
InternetCloseHandle(hInternet);
return response;
}
// Create request with timeout
DWORD flags = (urlComponents.nScheme == INTERNET_SCHEME_HTTPS) ? INTERNET_FLAG_SECURE : 0;
flags |= INTERNET_FLAG_RELOAD | INTERNET_FLAG_NO_CACHE_WRITE;
HINTERNET hRequest = HttpOpenRequestA(
hConnect,
"GET",
objectName.c_str(),
HTTP_VERSIONA,
NULL,
NULL,
flags,
0
);
if (!hRequest) {
response.statusText = "Failed to create HTTP request";
InternetCloseHandle(hConnect);
InternetCloseHandle(hInternet);
return response;
}
// Set request timeout
InternetSetOptionA(hRequest, INTERNET_OPTION_SEND_TIMEOUT, &timeoutMs, sizeof(timeoutMs));
InternetSetOptionA(hRequest, INTERNET_OPTION_RECEIVE_TIMEOUT, &timeoutMs, sizeof(timeoutMs));
std::cout << "Sending request with " << timeoutSeconds << " second timeout..." << std::endl;
DWORD startTime = GetTickCount();
// Send request
if (!HttpSendRequestA(hRequest, NULL, 0, NULL, 0)) {
DWORD error = GetLastError();
if (error == ERROR_INTERNET_TIMEOUT) {
response.statusText = "Request timed out after " + std::to_string(timeoutSeconds) + " seconds";
} else {
response.statusText = "Failed to send request. Error: " + std::to_string(error);
}
InternetCloseHandle(hRequest);
InternetCloseHandle(hConnect);
InternetCloseHandle(hInternet);
return response;
}
DWORD sendTime = GetTickCount() - startTime;
std::cout << "Request sent in " << sendTime << "ms" << std::endl;
// Get response (reuse code from previous functions)
DWORD statusCode = 0;
DWORD statusCodeSize = sizeof(statusCode);
HttpQueryInfoA(hRequest, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER,
&statusCode, &statusCodeSize, NULL);
response.statusCode = std::to_string(statusCode);
char statusText[256] = {0};
DWORD statusTextSize = sizeof(statusText);
HttpQueryInfoA(hRequest, HTTP_QUERY_STATUS_TEXT,
statusText, &statusTextSize, NULL);
response.statusText = statusText;
// Read response with timeout
DWORD bytesRead;
char bodyBuffer[8192];
std::string responseBody;
DWORD readStartTime = GetTickCount();
std::cout << "Reading response..." << std::endl;
while (InternetReadFile(hRequest, bodyBuffer, sizeof(bodyBuffer) - 1, &bytesRead) && bytesRead > 0) {
bodyBuffer[bytesRead] = '\0';
responseBody += bodyBuffer;
// Check if we're exceeding timeout
DWORD currentElapsed = GetTickCount() - readStartTime;
if (currentElapsed > timeoutMs) {
response.statusText = "Response reading timed out after " + std::to_string(timeoutSeconds) + " seconds";
response.statusCode = "408"; // Request Timeout
InternetCloseHandle(hRequest);
InternetCloseHandle(hConnect);
InternetCloseHandle(hInternet);
return response;
}
}
DWORD readTime = GetTickCount() - readStartTime;
std::cout << "Response read in " << readTime << "ms" << std::endl;
response.body = responseBody;
response.success = (statusCode >= 200 && statusCode < 300);
std::cout << "Request completed successfully" << std::endl;
// Cleanup
InternetCloseHandle(hRequest);
InternetCloseHandle(hConnect);
InternetCloseHandle(hInternet);
} catch (const std::exception& e) {
response.statusText = "Exception occurred: " + std::string(e.what());
std::cout << response.statusText << std::endl;
}
return response;
}
// Helper function to print response details
void PrintResponse(const HttpResponse& response) {
std::cout << "\n=== Response Details ===" << std::endl;
std::cout << "Status: " << response.statusCode << " " << response.statusText << std::endl;
std::cout << "Success: " << (response.success ? "Yes" : "No") << std::endl;
std::cout << "Headers (" << response.headers.size() << "):" << std::endl;
for (const auto& header : response.headers) {
std::cout << " " << header.first << ": " << header.second << std::endl;
}
std::cout << "\nBody (" << response.body.length() << " bytes):" << std::endl;
if (response.body.length() > 500) {
std::cout << response.body.substr(0, 250) << "..." << std::endl;
std::cout << "(showing first 250 of " << response.body.length() << " characters)" << std::endl;
} else {
std::cout << response.body << std::endl;
}
}
int main() {
std::cout << "=== C++ Windows Networking Examples ===" << std::endl;
std::cout << "Demonstrating HTTP requests using WinINet API\n" << std::endl;
try {
// Test 1: Simple GET request
std::cout << "1. Testing HTTP GET request..." << std::endl;
HttpResponse getResponse = HttpGet("https://httpbin.org/get");
PrintResponse(getResponse);
// Test 2: GET request with custom headers
std::cout << "\n\n2. Testing GET request with custom headers..." << std::endl;
std::map<std::string, std::string> headers = {
{"User-Agent", "C++ WinINet Client/1.0"},
{"Accept", "application/json"},
{"X-Custom-Header", "Test-Value"}
};
HttpResponse getWithHeadersResponse = HttpGet("https://httpbin.org/headers", headers);
PrintResponse(getWithHeadersResponse);
// Test 3: POST request with JSON data
std::cout << "\n\n3. Testing HTTP POST request..." << std::endl;
std::string jsonData = R"({"name": "C++ Client", "version": "1.0", "platform": "Windows"})";
HttpResponse postResponse = HttpPost("https://httpbin.org/post", jsonData);
PrintResponse(postResponse);
// Test 4: GET request with timeout
std::cout << "\n\n4. Testing HTTP request with timeout..." << std::endl;
HttpResponse timeoutResponse = HttpGetWithTimeout("https://httpbin.org/delay/2", 5);
PrintResponse(timeoutResponse);
// Test 5: Timeout test (should fail)
std::cout << "\n\n5. Testing timeout with long delay..." << std::endl;
HttpResponse timeoutFailResponse = HttpGetWithTimeout("https://httpbin.org/delay/10", 3);
PrintResponse(timeoutFailResponse);
// Test 6: File download (commented out to avoid creating files)
/*
std::cout << "\n\n6. Testing file download..." << std::endl;
bool downloadSuccess = DownloadFile(
"https://httpbin.org/bytes/1024",
"test_download.bin"
);
std::cout << "Download " << (downloadSuccess ? "successful" : "failed") << std::endl;
*/
std::cout << "\nAll networking examples completed successfully!" << std::endl;
} catch (const std::exception& e) {
std::cerr << "Unexpected error: " << e.what() << std::endl;
return 1;
}
return 0;
}
💻 Programmation Sockets TCP cpp
🟡 intermediate
⭐⭐⭐
Implémenter client et serveur TCP utilisant Windows Sockets (Winsock) avec gestion de connexion appropriée
⏱️ 25 min
🏷️ cpp, networking, tcp, sockets, windows
Prerequisites:
Windows Sockets API, TCP/IP protocol, Multithreading
#include <iostream>
#include <string>
#include <thread>
#include <vector>
#include <ws2tcpip.h>
#include <windows.h>
#pragma comment(lib, "ws2_32.lib")
// Constants
const int BUFFER_SIZE = 4096;
const int DEFAULT_PORT = 8080;
const int MAX_CLIENTS = 10;
// TCP Client class
class TcpClient {
private:
SOCKET socket_;
std::string serverAddress_;
int port_;
bool connected_;
public:
TcpClient() : socket_(INVALID_SOCKET), port_(DEFAULT_PORT), connected_(false) {}
~TcpClient() {
Disconnect();
}
bool Connect(const std::string& serverAddress, int port = DEFAULT_PORT) {
serverAddress_ = serverAddress;
port_ = port;
std::cout << "Connecting to " << serverAddress << ":" << port << std::endl;
// Create socket
socket_ = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (socket_ == INVALID_SOCKET) {
std::cout << "Failed to create socket. Error: " << WSAGetLastError() << std::endl;
return false;
}
// Setup server address
sockaddr_in serverAddr;
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(port);
// Convert IP address
if (inet_pton(AF_INET, serverAddress.c_str(), &serverAddr.sin_addr) != 1) {
std::cout << "Invalid IP address format" << std::endl;
closesocket(socket_);
return false;
}
// Connect to server
if (connect(socket_, (sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {
std::cout << "Failed to connect to server. Error: " << WSAGetLastError() << std::endl;
closesocket(socket_);
return false;
}
connected_ = true;
std::cout << "Connected to server successfully!" << std::endl;
return true;
}
bool Send(const std::string& data) {
if (!connected_) {
std::cout << "Not connected to server" << std::endl;
return false;
}
std::cout << "Sending " << data.length() << " bytes: " << data << std::endl;
int bytesSent = send(socket_, data.c_str(), data.length(), 0);
if (bytesSent == SOCKET_ERROR) {
std::cout << "Failed to send data. Error: " << WSAGetLastError() << std::endl;
return false;
}
if (bytesSent != (int)data.length()) {
std::cout << "Warning: Not all data was sent. Sent: " << bytesSent << " of " << data.length() << " bytes" << std::endl;
}
return true;
}
std::string Receive() {
if (!connected_) {
std::cout << "Not connected to server" << std::endl;
return "";
}
char buffer[BUFFER_SIZE];
int bytesReceived = recv(socket_, buffer, BUFFER_SIZE - 1, 0);
if (bytesReceived > 0) {
buffer[bytesReceived] = '\0';
std::string receivedData(buffer);
std::cout << "Received " << bytesReceived << " bytes: " << receivedData << std::endl;
return receivedData;
} else if (bytesReceived == 0) {
std::cout << "Connection closed by server" << std::endl;
connected_ = false;
} else {
std::cout << "Failed to receive data. Error: " << WSAGetLastError() << std::endl;
connected_ = false;
}
return "";
}
void Disconnect() {
if (connected_) {
closesocket(socket_);
connected_ = false;
std::cout << "Disconnected from server" << std::endl;
}
}
bool IsConnected() const {
return connected_;
}
};
// TCP Server class
class TcpServer {
private:
SOCKET listenSocket_;
std::vector<std::thread> clientThreads_;
std::vector<SOCKET> clientSockets_;
bool running_;
int port_;
void HandleClient(SOCKET clientSocket, const std::string& clientAddress) {
std::cout << "Client connected from " << clientAddress << std::endl;
char buffer[BUFFER_SIZE];
// Send welcome message
std::string welcome = "Welcome to TCP Server! Connected from " + clientAddress + "\n";
send(clientSocket, welcome.c_str(), welcome.length(), 0);
while (running_) {
// Receive data from client
int bytesReceived = recv(clientSocket, buffer, BUFFER_SIZE - 1, 0);
if (bytesReceived > 0) {
buffer[bytesReceived] = '\0';
std::string receivedData(buffer);
std::cout << "Received from " << clientAddress << ": " << receivedData << std::endl;
// Process received data and send response
std::string response = ProcessClientMessage(receivedData, clientAddress);
if (send(clientSocket, response.c_str(), response.length(), 0) == SOCKET_ERROR) {
std::cout << "Failed to send response to " << clientAddress << std::endl;
break;
}
// Check if client wants to disconnect
if (receivedData.find("quit") != std::string::npos ||
receivedData.find("exit") != std::string::npos) {
std::cout << "Client " << clientAddress << " requested disconnect" << std::endl;
break;
}
} else if (bytesReceived == 0) {
std::cout << "Client " << clientAddress << " disconnected" << std::endl;
break;
} else {
int error = WSAGetLastError();
if (error != WSAEWOULDBLOCK) {
std::cout << "Connection error with client " << clientAddress << ". Error: " << error << std::endl;
break;
}
}
// Small delay to prevent CPU spinning
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
// Clean up client connection
closesocket(clientSocket);
// Remove from client list
std::lock_guard<std::mutex> lock(clientMutex_);
auto it = std::find(clientSockets_.begin(), clientSockets_.end(), clientSocket);
if (it != clientSockets_.end()) {
clientSockets_.erase(it);
}
std::cout << "Connection with " << clientAddress << " closed" << std::endl;
}
std::string ProcessClientMessage(const std::string& message, const std::string& clientAddress) {
// Simple echo server with some additional processing
if (message.find("time") != std::string::npos) {
// Send current time
time_t now = time(nullptr);
char timeStr[100];
strftime(timeStr, sizeof(timeStr), "%Y-%m-%d %H:%M:%S", localtime(&now));
return std::string("Current time: ") + timeStr + "\n";
}
if (message.find("info") != std::string::npos) {
// Send server info
return std::string("TCP Server Info:\n") +
"Client: " + clientAddress + "\n" +
"Connected clients: " + std::to_string(clientSockets_.size()) + "\n" +
"Server running: " + (running_ ? "Yes" : "No") + "\n";
}
if (message.find("help") != std::string::npos) {
return std::string("Available commands:\n") +
" time - Get current server time\n" +
" info - Get server information\n" +
" echo - Echo message back\n" +
" quit - Disconnect from server\n" +
" help - Show this help message\n";
}
// Default echo response
return "Echo: " + message;
}
static std::mutex clientMutex_;
public:
TcpServer() : listenSocket_(INVALID_SOCKET), running_(false), port_(DEFAULT_PORT) {}
~TcpServer() {
Stop();
}
bool Start(int port = DEFAULT_PORT) {
port_ = port;
std::cout << "Starting TCP server on port " << port << std::endl;
// Create listening socket
listenSocket_ = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (listenSocket_ == INVALID_SOCKET) {
std::cout << "Failed to create listening socket. Error: " << WSAGetLastError() << std::endl;
return false;
}
// Setup server address
sockaddr_in serverAddr;
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = INADDR_ANY;
serverAddr.sin_port = htons(port);
// Bind socket
if (bind(listenSocket_, (sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {
std::cout << "Failed to bind socket. Error: " << WSAGetLastError() << std::endl;
closesocket(listenSocket_);
return false;
}
// Listen for connections
if (listen(listenSocket_, SOMAXCONN) == SOCKET_ERROR) {
std::cout << "Failed to listen. Error: " << WSAGetLastError() << std::endl;
closesocket(listenSocket_);
return false;
}
running_ = true;
std::cout << "TCP server started successfully on port " << port << std::endl;
// Start accepting connections in a separate thread
std::thread acceptThread(&TcpServer::AcceptConnections, this);
acceptThread.detach();
return true;
}
void AcceptConnections() {
while (running_) {
sockaddr_in clientAddr;
int clientAddrSize = sizeof(clientAddr);
// Accept connection
SOCKET clientSocket = accept(listenSocket_, (sockaddr*)&clientAddr, &clientAddrSize);
if (clientSocket != INVALID_SOCKET) {
// Get client IP address
char clientIP[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &clientAddr.sin_addr, clientIP, INET_ADDRSTRLEN);
std::string clientAddress = std::string(clientIP) + ":" + std::to_string(ntohs(clientAddr.sin_port));
// Set socket to non-blocking mode
u_long mode = 1; // 1 = non-blocking
ioctlsocket(clientSocket, FIONBIO, &mode);
{
std::lock_guard<std::mutex> lock(clientMutex_);
clientSockets_.push_back(clientSocket);
}
std::cout << "Accepted connection from " << clientAddress << std::endl;
// Start client handler thread
clientThreads_.emplace_back(&TcpServer::HandleClient, this, clientSocket, clientAddress);
} else {
int error = WSAGetLastError();
if (error != WSAEWOULDBLOCK) {
std::cout << "Accept failed. Error: " << error << std::endl;
}
}
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
}
void Stop() {
if (running_) {
std::cout << "Stopping TCP server..." << std::endl;
running_ = false;
// Close listening socket
if (listenSocket_ != INVALID_SOCKET) {
closesocket(listenSocket_);
listenSocket_ = INVALID_SOCKET;
}
// Close all client connections
{
std::lock_guard<std::mutex> lock(clientMutex_);
for (SOCKET clientSocket : clientSockets_) {
closesocket(clientSocket);
}
clientSockets_.clear();
}
// Wait for all client threads to finish
for (auto& thread : clientThreads_) {
if (thread.joinable()) {
thread.join();
}
}
clientThreads_.clear();
std::cout << "TCP server stopped" << std::endl;
}
}
bool IsRunning() const {
return running_;
}
int GetClientCount() const {
std::lock_guard<std::mutex> lock(clientMutex_);
return clientSockets_.size();
}
};
std::mutex TcpServer::clientMutex_;
// Initialize Winsock
bool InitializeWinsock() {
WSADATA wsaData;
int result = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (result != 0) {
std::cout << "WSAStartup failed. Error: " << result << std::endl;
return false;
}
if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
std::cout << "Winsock 2.2 not available" << std::endl;
WSACleanup();
return false;
}
std::cout << "Winsock 2.2 initialized successfully" << std::endl;
return true;
}
// Cleanup Winsock
void CleanupWinsock() {
WSACleanup();
std::cout << "Winsock cleaned up" << std::endl;
}
// 1. Simple client test
void TestSimpleClient() {
std::cout << "\n=== Simple TCP Client Test ===" << std::endl;
TcpClient client;
// Connect to a public echo server
if (client.Connect("tcpbin.com", 4242)) {
// Send test message
std::string message = "Hello from C++ TCP Client!";
if (client.Send(message)) {
// Receive response
std::string response = client.Receive();
if (!response.empty()) {
std::cout << "Echo response received: " << response << std::endl;
}
}
// Send another message
if (client.Send("What time is it?")) {
std::string response = client.Receive();
if (!response.empty()) {
std::cout << "Second response: " << response << std::endl;
}
}
client.Disconnect();
}
}
// 2. Local server test
void TestLocalServer() {
std::cout << "\n=== Local TCP Server Test ===" << std::endl;
TcpServer server;
if (server.Start(8080)) {
std::cout << "Server started. Connect with: telnet localhost 8080" << std::endl;
std::cout << "Available commands: time, info, help, quit\n" << std::endl;
// Run server for 30 seconds
std::this_thread::sleep_for(std::chrono::seconds(30));
std::cout << "Stopping server after 30 seconds..." << std::endl;
server.Stop();
}
}
// 3. Client connecting to local server
void TestClientToServer() {
std::cout << "\n=== Client to Local Server Test ===" << std::endl;
TcpServer server;
if (!server.Start(8081)) {
std::cout << "Failed to start server" << std::endl;
return;
}
// Give server time to start
std::this_thread::sleep_for(std::chrono::milliseconds(500));
// Connect client to server
TcpClient client;
if (client.Connect("127.0.0.1", 8081)) {
// Test commands
std::vector<std::string> commands = {
"help",
"time",
"info",
"Hello Server!",
"quit"
};
for (const std::string& command : commands) {
std::cout << "\nSending: " << command << std::endl;
if (client.Send(command + "\n")) {
std::string response = client.Receive();
if (!response.empty()) {
std::cout << "Server response: " << response << std::endl;
}
}
std::this_thread::sleep_for(std::chrono::milliseconds(500));
}
client.Disconnect();
}
server.Stop();
}
// 4. Multiple clients test
void TestMultipleClients() {
std::cout << "\n=== Multiple Clients Test ===" << std::endl;
TcpServer server;
if (!server.Start(8082)) {
std::cout << "Failed to start server" << std::endl;
return;
}
std::this_thread::sleep_for(std::chrono::milliseconds(500));
// Create multiple client threads
std::vector<std::thread> clientThreads;
for (int i = 1; i <= 3; i++) {
clientThreads.emplace_back([i]() {
TcpClient client;
if (client.Connect("127.0.0.1", 8082)) {
// Send client identification
std::string message = "Client " + std::to_string(i) + " is here!";
client.Send(message + "\n");
// Get welcome message
std::string welcome = client.Receive();
std::cout << "Client " << i << " received: " << welcome << std::endl;
// Send a few commands
client.Send("info\n");
std::string info = client.Receive();
std::cout << "Client " << i << " info: " << info << std::endl;
client.Send("quit\n");
client.Disconnect();
std::cout << "Client " << i << " disconnected" << std::endl;
}
});
}
// Let clients run
std::this_thread::sleep_for(std::chrono::seconds(5));
// Wait for all client threads to finish
for (auto& thread : clientThreads) {
if (thread.joinable()) {
thread.join();
}
}
server.Stop();
}
// 5. Connection failure test
void TestConnectionFailure() {
std::cout << "\n=== Connection Failure Test ===" << std::endl;
TcpClient client;
// Try to connect to non-existent server
std::cout << "Attempting to connect to non-existent server..." << std::endl;
if (!client.Connect("192.0.2.1", 8080)) { // RFC 5737 test address
std::cout << "Connection failed as expected (good test)" << std::endl;
} else {
std::cout << "Unexpected success connecting to test address" << std::endl;
client.Disconnect();
}
// Try to connect to invalid port
std::cout << "Attempting to connect to localhost on invalid port..." << std::endl;
if (!client.Connect("127.0.0.1", 99999)) {
std::cout << "Connection to invalid port failed as expected (good test)" << std::endl;
} else {
std::cout << "Unexpected success connecting to invalid port" << std::endl;
client.Disconnect();
}
}
int main() {
std::cout << "=== C++ Windows TCP Socket Examples ===" << std::endl;
std::cout << "Demonstrating TCP client/server communication using Winsock\n" << std::endl;
try {
// Initialize Winsock
if (!InitializeWinsock()) {
return 1;
}
// Run all tests
TestConnectionFailure();
TestSimpleClient();
TestClientToServer();
TestMultipleClients();
// Note: Uncomment the following to run an interactive server
// TestLocalServer();
std::cout << "\nAll TCP socket examples completed!" << std::endl;
// Cleanup Winsock
CleanupWinsock();
} catch (const std::exception& e) {
std::cerr << "Unexpected error: " << e.what() << std::endl;
CleanupWinsock();
return 1;
}
return 0;
}
💻 Serveur HTTP Simple cpp
🔴 complex
⭐⭐⭐⭐
Construire serveur HTTP basique utilisant Winsock avec analyse de requêtes et génération de réponses
⏱️ 35 min
🏷️ cpp, networking, http, server, windows
Prerequisites:
Advanced Winsock, HTTP protocol, Multithreading, Web development
#include <iostream>
#include <string>
#include <map>
#include <sstream>
#include <vector>
#include <thread>
#include <regex>
#include <ctime>
#include <ws2tcpip.h>
#include <windows.h>
#pragma comment(lib, "ws2_32.lib")
// Constants
const int BUFFER_SIZE = 8192;
const int DEFAULT_PORT = 8080;
const std::string SERVER_NAME = "C++ HTTP Server/1.0";
const std::string SERVER_VERSION = "1.0";
// HTTP Request structure
struct HttpRequest {
std::string method;
std::string path;
std::string version;
std::map<std::string, std::string> headers;
std::string body;
std::map<std::string, std::string> queryParams;
};
// HTTP Response structure
struct HttpResponse {
std::string version = "HTTP/1.1";
int statusCode = 200;
std::string statusText = "OK";
std::map<std::string, std::string> headers;
std::string body;
HttpResponse() {
headers["Server"] = SERVER_NAME;
headers["Connection"] = "close";
headers["Date"] = GetCurrentDateTime();
}
void SetContentType(const std::string& contentType) {
headers["Content-Type"] = contentType;
}
void SetContentLength() {
headers["Content-Length"] = std::to_string(body.length());
}
std::string ToString() const {
SetContentLength();
std::ostringstream response;
response << version << " " << statusCode << " " << statusText << "\r\n";
for (const auto& header : headers) {
response << header.first << ": " << header.second << "\r\n";
}
response << "\r\n" << body;
return response.str();
}
private:
static std::string GetCurrentDateTime() {
time_t now = time(nullptr);
struct tm timeinfo;
gmtime_s(&timeinfo, &now);
char buffer[100];
strftime(buffer, sizeof(buffer), "%a, %d %b %Y %H:%M:%S GMT", &timeinfo);
return std::string(buffer);
}
};
// 1. Parse HTTP request
HttpRequest ParseHttpRequest(const std::string& requestStr) {
HttpRequest request;
std::istringstream stream(requestStr);
std::string line;
// Parse request line
if (std::getline(stream, line)) {
// Remove CRLF
line.erase(line.find_last_not_of("\r") + 1);
std::istringstream requestLine(line);
std::string pathWithQuery;
requestLine >> request.method >> pathWithQuery >> request.version;
// Parse path and query parameters
size_t queryPos = pathWithQuery.find('?');
if (queryPos != std::string::npos) {
request.path = pathWithQuery.substr(0, queryPos);
std::string queryString = pathWithQuery.substr(queryPos + 1);
// Parse query parameters
std::istringstream queryStream(queryString);
std::string param;
while (std::getline(queryStream, param, '&')) {
size_t eqPos = param.find('=');
if (eqPos != std::string::npos) {
std::string key = param.substr(0, eqPos);
std::string value = param.substr(eqPos + 1);
request.queryParams[key] = value;
}
}
} else {
request.path = pathWithQuery;
}
}
// Parse headers
while (std::getline(stream, line)) {
line.erase(line.find_last_not_of("\r") + 1);
if (line.empty()) {
break; // End of headers
}
size_t colonPos = line.find(':');
if (colonPos != std::string::npos) {
std::string key = line.substr(0, colonPos);
std::string value = line.substr(colonPos + 1);
// Trim whitespace
key.erase(0, key.find_first_not_of(" \t"));
key.erase(key.find_last_not_of(" \t") + 1);
value.erase(0, value.find_first_not_of(" \t"));
value.erase(value.find_last_not_of(" \t") + 1);
// Convert header name to lowercase for consistent access
std::transform(key.begin(), key.end(), key.begin(), ::tolower);
request.headers[key] = value;
}
}
// Parse body (if present)
std::string remaining;
while (std::getline(stream, line)) {
remaining += line + "\n";
}
if (!remaining.empty()) {
request.body = remaining;
}
return request;
}
// 2. Create error responses
HttpResponse CreateErrorResponse(int statusCode, const std::string& message) {
HttpResponse response;
response.statusCode = statusCode;
response.statusText = GetStatusText(statusCode);
response.SetContentType("text/html");
std::ostringstream html;
html << "<!DOCTYPE html>\n";
html << "<html>\n";
html << "<head><title>Error " << statusCode << "</title></head>\n";
html << "<body>\n";
html << "<h1>Error " << statusCode << " - " << response.statusText << "</h1>\n";
html << "<p>" << message << "</p>\n";
html << "<hr>\n";
html << "<address>" << SERVER_NAME << "</address>\n";
html << "</body>\n";
html << "</html>\n";
response.body = html.str();
return response;
}
// 3. Get status text for status code
std::string GetStatusText(int statusCode) {
switch (statusCode) {
case 200: return "OK";
case 201: return "Created";
case 400: return "Bad Request";
case 401: return "Unauthorized";
case 403: return "Forbidden";
case 404: return "Not Found";
case 405: return "Method Not Allowed";
case 500: return "Internal Server Error";
case 501: return "Not Implemented";
default: return "Unknown";
}
}
// 4. Handle GET request
HttpResponse HandleGetRequest(const HttpRequest& request) {
std::cout << "Handling GET request for: " << request.path << std::endl;
// Route handling
if (request.path == "/") {
return HandleRootRequest();
} else if (request.path == "/about") {
return HandleAboutRequest();
} else if (request.path == "/time") {
return HandleTimeRequest();
} else if (request.path == "/echo") {
return HandleEchoRequest(request);
} else if (request.path == "/status") {
return HandleStatusRequest();
} else if (request.path == "/api/info") {
return HandleApiInfoRequest(request);
} else {
return CreateErrorResponse(404, "The requested resource was not found on this server.");
}
}
// 5. Handle POST request
HttpResponse HandlePostRequest(const HttpRequest& request) {
std::cout << "Handling POST request for: " << request.path << std::endl;
if (request.path == "/echo") {
return HandleEchoPostRequest(request);
} else if (request.path == "/api/data") {
return HandleApiDataRequest(request);
} else if (request.path == "/upload") {
return HandleUploadRequest(request);
} else {
return CreateErrorResponse(404, "The requested POST endpoint was not found on this server.");
}
}
// 6. Route handlers
HttpResponse HandleRootRequest() {
HttpResponse response;
response.SetContentType("text/html");
std::ostringstream html;
html << "<!DOCTYPE html>\n";
html << "<html>\n";
html << "<head>\n";
html << " <title>C++ HTTP Server</title>\n";
html << " <style>\n";
html << " body { font-family: Arial, sans-serif; margin: 40px; }\n";
html << " h1 { color: #333; }\n";
html << " .endpoint { background: #f5f5f5; padding: 10px; margin: 10px 0; border-radius: 5px; }\n";
html << " code { background: #e0e0e0; padding: 2px 4px; border-radius: 3px; }\n";
html << " </style>\n";
html << "</head>\n";
html << "<body>\n";
html << " <h1>Welcome to C++ HTTP Server!</h1>\n";
html << " <p>This is a simple HTTP server built with C++ and Winsock.</p>\n";
html << " <h2>Available Endpoints:</h2>\n";
html << " <div class='endpoint'><strong>GET /</strong> - This page</div>\n";
html << " <div class='endpoint'><strong>GET /about</strong> - Server information</div>\n";
html << " <div class='endpoint'><strong>GET /time</strong> - Current server time</div>\n";
html << " <div class='endpoint'><strong>GET /echo?message=hello</strong> - Echo query parameter</div>\n";
html << " <div class='endpoint'><strong>GET /status</strong> - Server status</div>\n";
html << " <div class='endpoint'><strong>GET /api/info</strong> - API information</div>\n";
html << " <div class='endpoint'><strong>POST /echo</strong> - Echo request body</div>\n";
html << " <div class='endpoint'><strong>POST /api/data</strong> - Accept JSON data</div>\n";
html << " <div class='endpoint'><strong>POST /upload</strong> - File upload simulation</div>\n";
html << "</body>\n";
html << "</html>\n";
response.body = html.str();
return response;
}
HttpResponse HandleAboutRequest() {
HttpResponse response;
response.SetContentType("text/html");
std::ostringstream html;
html << "<!DOCTYPE html>\n";
html << "<html>\n";
html << "<head><title>About - C++ HTTP Server</title></head>\n";
html << "<body>\n";
html << "<h1>About This Server</h1>\n";
html << "<ul>\n";
html << "<li><strong>Name:</strong> " << SERVER_NAME << "</li>\n";
html << "<li><strong>Version:</strong> " << SERVER_VERSION << "</li>\n";
html << "<li><strong>Protocol:</strong> HTTP/1.1</li>\n";
html << "<li><strong>Platform:</strong> Windows (Winsock)</li>\n";
html << "<li><strong>Language:</strong> C++</li>\n";
html << "</ul>\n";
html << "<p>Built as a demonstration of basic HTTP server functionality.</p>\n";
html << "</body>\n";
html << "</html>\n";
response.body = html.str();
return response;
}
HttpResponse HandleTimeRequest() {
HttpResponse response;
response.SetContentType("text/plain");
time_t now = time(nullptr);
char buffer[100];
ctime_s(buffer, sizeof(buffer), &now);
response.body = std::string("Current server time: ") + buffer;
return response;
}
HttpResponse HandleEchoRequest(const HttpRequest& request) {
HttpResponse response;
response.SetContentType("text/html");
std::ostringstream html;
html << "<!DOCTYPE html>\n";
html << "<html>\n";
html << "<head><title>Echo Response</title></head>\n";
html << "<body>\n";
html << "<h1>Echo Request</h1>\n";
html << "<p><strong>Path:</strong> " << request.path << "</p>\n";
html << "<p><strong>Method:</strong> " << request.method << "</p>\n";
html << "<p><strong>Query Parameters:</strong></p>\n";
html << "<ul>\n";
for (const auto& param : request.queryParams) {
html << "<li><em>" << param.first << "</em> = " << param.second << "</li>\n";
}
if (request.queryParams.empty()) {
html << "<li><em>No query parameters found</em></li>\n";
}
html << "</ul>\n";
html << "</body>\n";
html << "</html>\n";
response.body = html.str();
return response;
}
HttpResponse HandleEchoPostRequest(const HttpRequest& request) {
HttpResponse response;
response.SetContentType("text/html");
std::ostringstream html;
html << "<!DOCTYPE html>\n";
html << "<html>\n";
html << "<head><title>POST Echo Response</title></head>\n";
html << "<body>\n";
html << "<h1>POST Request Echo</h1>\n";
html << "<p><strong>Request Body:</strong></p>\n";
html << "<pre>" << request.body << "</pre>\n";
html << "<p><strong>Body Length:</strong> " << request.body.length() << " bytes</p>\n";
html << "</body>\n";
html << "</html>\n";
response.body = html.str();
return response;
}
HttpResponse HandleStatusRequest() {
HttpResponse response;
response.SetContentType("application/json");
std::ostringstream json;
json << "{\n";
json << " \"status\": \"running\",\n";
json << " \"uptime\": \"" << GetUptime() << "\",\n";
json << " \"memory\": \"" << GetMemoryUsage() << "\",\n";
json << " \"connections\": \"" << GetConnectionCount() << "\"\n";
json << "}\n";
response.body = json.str();
return response;
}
HttpResponse HandleApiInfoRequest(const HttpRequest& request) {
HttpResponse response;
response.SetContentType("application/json");
std::ostringstream json;
json << "{\n";
json << " \"name\": \"" << SERVER_NAME << "\",\n";
json << " \"version\": \"" << SERVER_VERSION << "\",\n";
json << " \"endpoints\": [\n";
json << " \"GET /\",\n";
json << " \"GET /about\",\n";
json << " \"GET /time\",\n";
json << " \"GET /echo\",\n";
json << " \"GET /status\",\n";
json << " \"POST /echo\",\n";
json << " \"POST /api/data\",\n";
json << " \"POST /upload\"\n";
json << " ],\n";
json << " \"request\": {\n";
json << " \"method\": \"" << request.method << "\",\n";
json << " \"path\": \"" << request.path << "\",\n";
json << " \"query\": {";
bool first = true;
for (const auto& param : request.queryParams) {
if (!first) json << ",";
json << "\"" << param.first << "\": \"" << param.second << "\"";
first = false;
}
json << "}\n";
json << " }\n";
json << "}\n";
response.body = json.str();
return response;
}
HttpResponse HandleApiDataRequest(const HttpRequest& request) {
HttpResponse response;
response.SetContentType("application/json");
std::ostringstream json;
json << "{\n";
json << " \"status\": \"received\",\n";
json << " \"message\": \"Data received successfully\",\n";
json << " \"data\": \"" << request.body << "\",\n";
json << " \"timestamp\": \"" << GetCurrentDateTime() << "\"\n";
json << "}\n";
response.body = json.str();
return response;
}
HttpResponse HandleUploadRequest(const HttpRequest& request) {
HttpResponse response;
response.SetContentType("text/html");
std::ostringstream html;
html << "<!DOCTYPE html>\n";
html << "<html>\n";
html << "<head><title>Upload Simulation</title></head>\n";
html << "<body>\n";
html << "<h1>Upload Simulation</h1>\n";
html << "<p>Received " << request.body.length() << " bytes of data.</p>\n";
html << "<p><strong>Content-Type:</strong> " << request.headers["content-type"] << "</p>\n";
html << "<p><strong>Content-Length:</strong> " << request.headers["content-length"] << "</p>\n";
html << "<p><em>This is a simulated upload - the data is not actually saved.</em></p>\n";
html << "</body>\n";
html << "</html>\n";
response.body = html.str();
return response;
}
// Helper functions
std::string GetCurrentDateTime() {
time_t now = time(nullptr);
struct tm timeinfo;
gmtime_s(&timeinfo, &now);
char buffer[100];
strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S GMT", &timeinfo);
return std::string(buffer);
}
std::string GetUptime() {
static DWORD startTime = GetTickCount();
DWORD uptime = GetTickCount() - startTime;
DWORD seconds = uptime / 1000;
DWORD minutes = seconds / 60;
DWORD hours = minutes / 60;
seconds %= 60;
minutes %= 60;
std::ostringstream oss;
oss << hours << "h " << minutes << "m " << seconds << "s";
return oss.str();
}
std::string GetMemoryUsage() {
PROCESS_MEMORY_COUNTERS pmc;
if (GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc))) {
DWORD memoryMB = pmc.WorkingSetSize / (1024 * 1024);
return std::to_string(memoryMB) + " MB";
}
return "Unknown";
}
int GetConnectionCount() {
// In a real server, this would track active connections
return 1; // Mock value
}
// 7. Process HTTP request
HttpResponse ProcessRequest(const HttpRequest& request) {
std::cout << "Processing " << request.method << " " << request.path << std::endl;
if (request.method == "GET") {
return HandleGetRequest(request);
} else if (request.method == "POST") {
return HandlePostRequest(request);
} else if (request.method == "HEAD") {
HttpResponse response = HandleGetRequest(request);
response.body = ""; // HEAD requests don't include body
return response;
} else {
return CreateErrorResponse(405, "Method not allowed. Use GET, POST, or HEAD.");
}
}
// 8. Handle client connection
void HandleClient(SOCKET clientSocket, const std::string& clientAddress) {
char buffer[BUFFER_SIZE];
int bytesReceived;
std::cout << "New connection from " << clientAddress << std::endl;
// Receive request
std::string requestStr;
while ((bytesReceived = recv(clientSocket, buffer, BUFFER_SIZE - 1, 0)) > 0) {
buffer[bytesReceived] = '\0';
requestStr += buffer;
// Check if we have the complete request (headers + blank line)
if (requestStr.find("\r\n\r\n") != std::string::npos) {
break;
}
}
if (bytesReceived > 0) {
std::cout << "Received request (" << requestStr.length() << " bytes) from " << clientAddress << std::endl;
std::cout << "Request preview: " << requestStr.substr(0, std::min(200, (int)requestStr.length())) << "..." << std::endl;
try {
// Parse and process request
HttpRequest request = ParseHttpRequest(requestStr);
HttpResponse response = ProcessRequest(request);
// Send response
std::string responseStr = response.ToString();
std::cout << "Sending response (" << responseStr.length() << " bytes) to " << clientAddress << std::endl;
std::cout << "Response status: " << response.statusCode << " " << response.statusText << std::endl;
if (send(clientSocket, responseStr.c_str(), responseStr.length(), 0) == SOCKET_ERROR) {
std::cout << "Failed to send response to " << clientAddress << std::endl;
} else {
std::cout << "Response sent successfully to " << clientAddress << std::endl;
}
} catch (const std::exception& e) {
std::cout << "Error processing request from " << clientAddress << ": " << e.what() << std::endl;
HttpResponse errorResponse = CreateErrorResponse(500, "Internal server error");
std::string errorResponseStr = errorResponse.ToString();
send(clientSocket, errorResponseStr.c_str(), errorResponseStr.length(), 0);
}
} else if (bytesReceived == 0) {
std::cout << "Client " << clientAddress << " disconnected" << std::endl;
} else {
std::cout << "Error receiving from " << clientAddress << std::endl;
}
closesocket(clientSocket);
std::cout << "Connection with " << clientAddress << " closed" << std::endl;
}
// 9. HTTP Server class
class HttpServer {
private:
SOCKET listenSocket_;
bool running_;
int port_;
std::vector<std::thread> clientThreads_;
public:
HttpServer() : listenSocket_(INVALID_SOCKET), running_(false), port_(DEFAULT_PORT) {}
~HttpServer() {
Stop();
}
bool Start(int port = DEFAULT_PORT) {
port_ = port;
std::cout << "Starting HTTP server on port " << port << std::endl;
std::cout << "Server URL: http://localhost:" << port << std::endl;
// Create listening socket
listenSocket_ = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (listenSocket_ == INVALID_SOCKET) {
std::cout << "Failed to create listening socket. Error: " << WSAGetLastError() << std::endl;
return false;
}
// Set socket options
BOOL opt = TRUE;
setsockopt(listenSocket_, SOL_SOCKET, SO_REUSEADDR, (char*)&opt, sizeof(opt));
// Setup server address
sockaddr_in serverAddr;
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = INADDR_ANY;
serverAddr.sin_port = htons(port);
// Bind socket
if (bind(listenSocket_, (sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {
std::cout << "Failed to bind socket. Error: " << WSAGetLastError() << std::endl;
closesocket(listenSocket_);
return false;
}
// Listen for connections
if (listen(listenSocket_, SOMAXCONN) == SOCKET_ERROR) {
std::cout << "Failed to listen. Error: " << WSAGetLastError() << std::endl;
closesocket(listenSocket_);
return false;
}
running_ = true;
std::cout << "HTTP server started successfully!" << std::endl;
std::cout << "Press Ctrl+C to stop the server\n" << std::endl;
// Start accepting connections
while (running_) {
sockaddr_in clientAddr;
int clientAddrSize = sizeof(clientAddr);
SOCKET clientSocket = accept(listenSocket_, (sockaddr*)&clientAddr, &clientAddrSize);
if (clientSocket != INVALID_SOCKET) {
// Get client IP address
char clientIP[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &clientAddr.sin_addr, clientIP, INET_ADDRSTRLEN);
std::string clientAddress = std::string(clientIP) + ":" + std::to_string(ntohs(clientAddr.sin_port));
// Handle client in a separate thread
clientThreads_.emplace_back(HandleClient, clientSocket, clientAddress);
} else {
int error = WSAGetLastError();
if (error != WSAEINTR) { // Not interrupted
std::cout << "Accept failed. Error: " << error << std::endl;
}
}
}
// Wait for all client threads to finish
for (auto& thread : clientThreads_) {
if (thread.joinable()) {
thread.join();
}
}
return true;
}
void Stop() {
if (running_) {
std::cout << "\nStopping HTTP server..." << std::endl;
running_ = false;
if (listenSocket_ != INVALID_SOCKET) {
closesocket(listenSocket_);
listenSocket_ = INVALID_SOCKET;
}
// Wait for all client threads
for (auto& thread : clientThreads_) {
if (thread.joinable()) {
thread.join();
}
}
clientThreads_.clear();
std::cout << "HTTP server stopped" << std::endl;
}
}
};
// Initialize Winsock
bool InitializeWinsock() {
WSADATA wsaData;
int result = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (result != 0) {
std::cout << "WSAStartup failed. Error: " << result << std::endl;
return false;
}
if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
std::cout << "Winsock 2.2 not available" << std::endl;
WSACleanup();
return false;
}
std::cout << "Winsock 2.2 initialized successfully" << std::endl;
return true;
}
// Cleanup Winsock
void CleanupWinsock() {
WSACleanup();
std::cout << "Winsock cleaned up" << std::endl;
}
int main() {
std::cout << "=== C++ Windows HTTP Server Examples ===" << std::endl;
std::cout << "Demonstrating HTTP server implementation using Winsock\n" << std::endl;
try {
// Initialize Winsock
if (!InitializeWinsock()) {
return 1;
}
// Create and start HTTP server
HttpServer server;
// Handle Ctrl+C to gracefully stop server
SetConsoleCtrlHandler([](DWORD ctrlType) -> BOOL {
if (ctrlType == CTRL_C_EVENT) {
std::cout << "\nCtrl+C pressed. Stopping server..." << std::endl;
return TRUE;
}
return FALSE;
}, TRUE);
// Start server on port 8080
if (!server.Start(8080)) {
std::cout << "Failed to start server" << std::endl;
CleanupWinsock();
return 1;
}
// Server runs until user presses Ctrl+C or stops automatically
std::cout << "HTTP server examples completed!" << std::endl;
// Cleanup Winsock
CleanupWinsock();
} catch (const std::exception& e) {
std::cerr << "Unexpected error: " << e.what() << std::endl;
CleanupWinsock();
return 1;
}
return 0;
}