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;
}