• HTTP 代理服务器的设计与实现(C++)


    实验内容

    1. 设计并实现一个基本 HTTP 代理服务器。要求在指定端口(例如 8080)接收来自客户的 HTTP 请求并且根据其中的 URL 地址访问该地址 所指向的 HTTP 服务器(原服务器),接收 HTTP 服 务器的响应报文,并 将响应报文转发给对应的客户进行浏览。
    2. 设计并实现一个支持 Cache 功能的 HTTP 代理服务器。要求能缓 存原服务器响应的对象,并 能够通过修改请求报文(添加 if-modified-since 头行),向原服务器确认缓存对象是否是最新版本。 (选作内容)
    3. 扩展 HTTP 代理服务器,支持如下功能: (选作内容)
      1. 网站过滤:允许/不允许访问某些网站;
      2. 用户过滤:支持/不支持某些用户访问外部网站;
      3. 网站引导:将用户对某个网站的访问引导至一个模拟网站(钓鱼)。

    代理服务器的概念

    代理服务器,允许一个网络终端(一般为客户端)通过这个服务与另一 个网络终端(一般为服务器)进行非直接的连接。普通 Web 应用通信方式与采用代理服务器的 通信方式的对比如下图所示:

    代理服务器在指定端口(本实验中所指定的是666端口)监听浏览器的访问请求(需要在客户端浏览器进行相应的设置),接收到浏览器对远程网站的浏览请求时,代理服务器开始在代理服务器的缓存中检索 URL 对应的对象(网页、 图像等对象),找到对象文件后,提取该对象文件的最新被修改时间;代理服务器程序在客户的请求报文首部插入,并向原 Web 服务器转发修改后的请求报文。如果代理服务器没有该对象的缓存,则会直接向原服务器转发请求报文,并将原服务器返回的响应直接转发给客户端,同时将对象缓存到代理服务器中。代理服务器程序会根据缓存的时间、大小和提取记录等对缓存进行清理。

    代码结构

    代码中共实现 3个类,分别为WebsiteDetector类、Cache类和HttpProxyServer类。

    WebsiteDetector类:

    该类实现了网站过滤和网站引导功能。通过构造函数直接静态设置了钓鱼网站和屏蔽的网站:

    WebsiteDetector::WebsiteDetector() 
    {
    	AddValidURL("http://jwc.hit.edu.cn/","http://jwts.hit.edu.cn/");
    	AddBlockedURL("http://xltj.hit.edu.cn/");
    }

    可知,屏蔽了心理网站。将教务处网站引导到本科教学管理与服务平台。

    Cache

    该类在当前目录下创建文件夹.cache/,在其中存储浏览缓存对象。同时该类中,保存着对象与文件名的映射关系,对象和LastModified字段的映射关系。

    class Cache {
    
    public:
    
    std::string GetDate(const std::string& url); // 获取url对应保存的LastModified字段
    
    bool Get(const std::string& url, char* response, size_t& start, size_t& responseSize); // 读取缓存
    
    bool Put(const std::string& url, const char* response, size_t responseSize, size_t& start); // 保存缓存
    
    private:
    
    ​      std::string cacheDirectory_; // 存放缓存的文件目录
    
    ​      std::map cacheMap_; // 对象和LastModified字段的映射关系
    
    ​      std::map fileMap_; / 对象与文件名的映射关系
    
    ​      std::mutex mutex_; // 多线程同时读写文件的互斥锁
    
    };

    HttpProxyServer

    该类是代理服务器的实现类。是一个多用户代理服务器。首先该类创建HTTP代理服务的TCP主套接字,该套接字监听等待客户端的连接请求。当客户端连接之后,创建一个子线程,由子线程行上述一对一的代理过程,服务结束之后子线程终止。

    class HttpProxyServer
    
    {
    
    public:
    
    	HttpProxyServer(int port); // 构造函数,参数为端口号
    
    	void Start(); // 监听客户端连接请求
    
    private:
    
    	int serverSocket_; // 代理服务Socket
    
    	int port_; // 端口号
    
    	struct sockaddr_in serverAddr_; // 代理服务地址
    
    	Cache cache_; // Cache类
    
    	WebsiteDetector websiteDetector_; // websiteDetector类
    
    	void HandleClient(int clientSocket); // 子线程调用函数
    
    	std::string ExtractUrl(const std::string &httpRequest); // 解析URL
    
    	int CreateServerSocket(const std::string &host); // 创建与原服务器连接的Socket
    
    	bool ServerToClient(const std::string &url, int clientSocket); // 转发数据
    
    	void ParseUrl(const std::string &url, std::string &host, std::string &path); // 解析主机名与路径名
    
    };

    程序基本流程

    (1) 初始化服务器Socket,监听等待客户端的连接请求。

    (2) 当客户端连接后,创建子线程处理请求。

    (3) 子线程接收请求,解析HTTP请求的首部行和请求头。然后提取Url,Url作为参数通过websiteDetector类判断是否屏蔽或者引导。

    (4) 然后进入转发的过程,首先进行域名解析,然后创建Socket先原服务器发送请求,接收响应,将数据转发到客户端。

    (5) 在转发的过程中,涉及保存缓存和读取缓存。

    网站引导功

    利用首部行中的location字段,实现引导。

    std::string locationResponse = std::string("HTTP/1.1 302 Found") + MY_CRLF + "Location: " + newUrl + MY_CRLF + MY_CRLF;
    
    send(clientSocket, locationResponse.c_str(), locationResponse.size(), 0);

    用户过滤功能

    设置服务器地址信息时实现。

    serverAddr_.sin_addr.s_addr = INADDR_ANY;
    
    // serverAddr_.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); //只允许本机用户访问服务器

    Cache功能

    1. 代理服务器处理客户端请求时,对于第一次出现的对象,会保存下。当客户端再次请求时,代理服务器就会在请求中添加If-Modified-Since首部行。

    date = cache_.GetDate(url);
    std::string cacheRequest = httpRequest + "If-Modified-Since: " + date + MY_CRLF + MY_CRLF;
    1. 发送该请求后,等待原服务器响应,并判断是否回应304状态码。
    if (IsResponseNotModified(responseNotModified) ) {
    // std::cout << "304 Not Modified" << std::endl;
    ​      sel = false;
    }else {
    ​      cache_.ClearFileContent(url); //清空
    ​      sel = true;
    }
    1. sel为false时,则读取Cache转发到客户端。若为true,则发送HTTP请求到原服务器,再接收响应,转发到客户端,再保存到Cache。

    修改Chrome浏览器代理配置

    --proxy-server="http://127.0.0.1:666"

    VScode编译运行

    该代理服务器成功在666端口启动,并输出了cache目录。

    验证

    验证基础的代理功能

    访问今日哈工大网站:http://today.hit.edu.cn

    可以看到,网站资源顺利加载,输出栏中,输出了请求的各个资源对象的url。

    验证网站引导功能

    输入网址:http://jwc.hit.edu.cn/

    最后直接跳转到到了,http://jwts.hit.edu.cn/

    验证网站过滤功能

    输入网址:http://xltj.hit.edu.cn/

    可以看到,无法访问。

    验证用户过滤功能

    验证Cache功能

    将在Cache中的资源 http://jwts.hit.edu.cn/resources/css/common/ydy.css ,修改一下。

    把色彩均改为红色,再次访问 http://jwts.hit.edu.cn/

    可以看到,字体颜色变为红色。可知,HTTP代理服务器这次使用的是Cache中的资源。

    源代码

    点击查看代码
    //g++ your_code.cpp -o your_executable -lws2_32
    
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    
    
    #define MAX_CLIENTS 6
    #define BUFSIZE 655360
    #define HEADSIZE 128
    #define MY_CRLF "\r\n"
    
    class WebsiteDetector {
    public:
        WebsiteDetector() 
        {
            AddValidURL("http://jwc.hit.edu.cn/", "http://jwts.hit.edu.cn/");
            AddBlockedURL("http://xltj.hit.edu.cn/");
        }
        // 钓鱼
        std::string IsURLPhishing(const std::string& url) {
            auto it = validURLs_.find(url);
            if (it != validURLs_.end()) {
                return it->second;
            } else {
                return "Phishing";
            }
        }
        // 屏蔽
        bool IsURLBlocked(const std::string& url) {
            for (const std::string& blockedURL : blockedURLs_) {
                 if (url.find(blockedURL) != std::string::npos) {
                    return true;
                }
            }
            return false;
        }
    private:
        std::map validURLs_;
        std::vector blockedURLs_;
    
        void AddValidURL(const std::string& srcURL, const std::string& dstURL) 
        {
            validURLs_[srcURL] = dstURL;
        }
    
        void AddBlockedURL(const std::string& url) {
            blockedURLs_.push_back(url);
        }
    };
    
    class Cache {
    public:
       
        Cache() : cacheDirectory_("H:\\cppwork\\CS-networking\\.cache") {
            std::cout << cacheDirectory_ << std::endl;
            std::system(("mkdir -p " + cacheDirectory_).c_str());
        }
        bool Check(const std::string& url) {
            std::lock_guard lock(mutex_);
            auto it = cacheMap_.find(url);
            if (it != cacheMap_.end()) 
            {
                return true;
            }
            return false;
        }
        // 清空文件内容
        bool ClearFileContent(const std::string& url) {
            std::lock_guard lock(mutex_);
    
            // Generate a unique filename based on the URL
            std::string fileName = GetFileNameFromUrl(url);
            auto it = fileMap_.find(fileName);
            std::string fileTag = it->second;
    
            std::string filePath = cacheDirectory_ + "\\" + fileTag;
            // 打开文件并使用 std::ios::trunc 模式来清空文件内容
            std::ofstream file(filePath, std::ios::out | std::ios::trunc);
            if (!file) {
                std::cerr << "无法打开文件:" << filePath << std::endl;
                return false;
            }
            // 关闭文件
            file.close();
            return true;
        }
        std::string GetDate(const std::string& url) 
        {
            std::lock_guard lock(mutex_);
            auto it = cacheMap_.find(url);
            return it->second;
        }
        bool Get(const std::string& url, char* response, size_t& start, size_t& responseSize) {
            std::lock_guard lock(mutex_);
    
            // Generate a unique filename based on the URL
            std::string fileName = GetFileNameFromUrl(url);
            std::string fileTag = fileMap_[fileName];
    
            std::cout << "Get() url: " << url << std::endl;
            std::cout << "Get() fileTag: " << fileTag << std::endl;
            // If found, read the response from the file
            std::ifstream file(cacheDirectory_ + "\\" + fileTag, std::ios::binary);
            if (file) {
                file.seekg(start, std::ios::beg);
                file.read(response, BUFSIZE);
                // Get the number of bytes read in this chunk
                size_t bytesRead = static_cast<size_t>(file.gcount());
                start += bytesRead;
                responseSize = bytesRead;
                response[bytesRead] = '\0';
                file.close();
                return true;
            }
            return false; // URL not found in the cache
        }
    
        bool Put(const std::string& url, const char* response, size_t responseSize, size_t& start) {
            std::lock_guard lock(mutex_);
    
            // Generate a unique filename based on the URL
            std::string fileName = GetFileNameFromUrl(url);
            auto it = fileMap_.find(fileName);
            std::string fileTag;
            if (it == fileMap_.end()) 
            {
                fileTag = std::to_string(cnt);
                fileMap_[fileName] = fileTag;
                cnt ++;
            }else 
            {
                fileTag = it->second;
            }
    
            // Store the response in a file
            std::ofstream file(cacheDirectory_ + "\\" + fileTag, std::ios::binary | std::ios::app );
            if (!file) {
                fprintf(stderr, "file open error: %s(errno: %d)\n", strerror(errno),errno);
                return false; // Unable to open file for writing
            }
            file.seekp(start);
            file.write(response, responseSize);
            file.close();
            start += responseSize;
            return true; // Failed to store response in the cache
        }
    
        void PutDate(const std::string& url)
        {
            std::lock_guard lock(mutex_);
            // Generate a unique filename based on the URL
            std::string fileName = GetFileNameFromUrl(url);
            std::string fileTag = fileMap_[fileName];
            // 拼接完整的文件路径
            std::string filePath = cacheDirectory_ + "\\" + fileTag;
    
            // 打开文件并读取 Last-Modified 首部内容
            std::ifstream file(filePath);
            if (!file) {
                fprintf(stderr, "file open error: %s(errno: %d)\n", strerror(errno),errno);
            }
            std::string line;
            while (std::getline(file, line)) {
                // 查找包含 Last-Modified 首部的行
                if (line.find("Last-Modified:") != std::string::npos) {
                    // 提取 Last-Modified 的值并存储到 cacheMap_
                    size_t startPos = line.find(":") + 2;
                    size_t endPos = line.find(MY_CRLF);
                    std::string date = line.substr(startPos, endPos);
                    // std::cout << "line: " << line << std::endl;
                    // std::cout << "date: " << date << std::endl;
                    cacheMap_[url] = date;
                    break; // 找到后可以退出循环
                }else
                {
                    if (line == MY_CRLF)
                    {   
                        break;
                    }
                }
            }
            file.close();
        }
    
        
    private:
        std::string cacheDirectory_;
        std::map cacheMap_;
        std::map fileMap_;
        std::mutex mutex_;
        int cnt = 1;
    
        std::string GetFileNameFromUrl(const std::string& url) {
            // Replace characters in the URL to create a valid filename
            std::string fileName = url;
            for (char& c : fileName) {
                if (c == '/' || c == '?' || c == '&' || c == '=') {
                    c = '_';
                }
            }
            return fileName;
        }
    };
    
    
    // 定义HTTP代理服务器类
    class HttpProxyServer
    {
    public:
        HttpProxyServer(int port) : port_(port)
        {
            
            // 初始化服务器
            // 创建主套接字并绑定端口
            serverSocket_ = socket(AF_INET, SOCK_STREAM, 0);
            if (serverSocket_ == -1)
            {
                fprintf(stderr, "Constructor(): create socket error: %s(errno: %d)\n", strerror(errno),errno);
                exit(EXIT_FAILURE);
            }
    
            // 设置服务器地址信息
            // 初始化 serverAddr_
            memset(&serverAddr_, 0, sizeof(serverAddr_));
            serverAddr_.sin_family = AF_INET;
            serverAddr_.sin_addr.s_addr = INADDR_ANY;
            // serverAddr_.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); //只允许本机用户访问服务器
            serverAddr_.sin_port = htons(port_);
    
            // 绑定套接字到指定端口
            if (bind(serverSocket_, (struct sockaddr *)&serverAddr_, sizeof(serverAddr_)) == -1)
            {
                fprintf(stderr, "Constructor(): bind socket error: %s(errno: %d)\n",strerror(errno), errno);
                closesocket(serverSocket_);
                exit(EXIT_FAILURE);
            }
    
            // 开始监听客户端连接请求
            if (listen(serverSocket_, MAX_CLIENTS) == -1)
            {
                fprintf(stderr, "Constructor(): listen socket error: %s(errno: %d)\n",strerror(errno),errno);
                closesocket(serverSocket_);
                exit(EXIT_FAILURE);
            }
    
            std::cout << "Proxy server started on port " << port_ << std::endl;
        }
    
        void Start()
        {
            // 启动服务器,监听客户端连接请求
            while (true)
            {
                struct sockaddr_in clientAddr;
                int clientAddrLen = sizeof(struct sockaddr);
    
                // 接受客户端连接
                int clientSocket = accept(serverSocket_, (struct sockaddr *)&clientAddr, &clientAddrLen);
                if (clientSocket == INVALID_SOCKET)
                {
                    fprintf(stderr, "Start(): accept socket error: %s(errno: %d)",strerror(errno),errno);
                    continue; // 继续等待下一个连接
                }
    
                // std::cout << "Start(): Accepted a client connection" << std::endl;
    
                // 创建子线程处理客户端请求
                std::thread clientThread(&HttpProxyServer::HandleClient, this, clientSocket);
                clientThread.detach(); // 不等待
            }
        }
    
    private:
        int serverSocket_;
        int port_;
        struct sockaddr_in serverAddr_;
        Cache cache_;
        WebsiteDetector websiteDetector_;
    
        void HandleClient(int clientSocket)
        {
            // 读取客户端的HTTP请求
            char buffer[BUFSIZE];
            memset(buffer, 0, BUFSIZE);
            ssize_t bytesRead = recv(clientSocket, buffer, BUFSIZE - 1, 0);
            if (bytesRead == -1)
            {
                perror("HandleClient(): Error reading from client socket");
                closesocket(clientSocket);
                return;
            }
    
            // 解析请求,提取URL
            std::string request(buffer);
            std::string url = ExtractUrl(request);
    
            std::cout << "<" << url << ">" << std::endl;
            
            // Website Filter; User Filter ; Website phishing
            if (websiteDetector_.IsURLBlocked(url))
            {
                std::cout << "Url Blocked Success: " << url << std::endl;
            }else
            {
                std::string newUrl = websiteDetector_.IsURLPhishing(url);
                if (newUrl == "Phishing")
                {
                    // 向服务端请求,向客户端发送
                    if( ServerToClient(url, clientSocket) )
                    {
                        std::cout << "Transmit Success!" << std::endl;
                    }else
                    {
                        std::cout << "Transmit Fail!" << std::endl;
                    }
                }else
                {
                    std::cout << "Phishing" << std::endl;
                    std::string locationResponse = std::string("HTTP/1.1 302 Found") + MY_CRLF + "Location: " + newUrl + MY_CRLF + MY_CRLF;
                    std::cout << locationResponse << std::endl;
                    send(clientSocket, locationResponse.c_str(), locationResponse.size(), 0);
                }
                
            }
    
            std::cout << "----------------------" << std::endl;
            // 关闭连接
            closesocket(clientSocket);
        }
    
        // 提取URL
        std::string ExtractUrl(const std::string &httpRequest)
        {
            std::string url;
            // Debug
            // std::cout << "ExtractUrl(): httpRequest = " << std::endl << httpRequest << std::endl;
    
            // 在HTTP请求中查找"GET ",通常URL紧随其后
            size_t getPos = httpRequest.find("GET ");
            if (getPos != std::string::npos)
            {
                // 找到"GET "后,查找下一个空格,该空格之后是URL
                size_t spacePos = httpRequest.find(' ', getPos + 4);
                if (spacePos != std::string::npos)
                {
                    url = httpRequest.substr(getPos + 4, spacePos - (getPos + 4));
                }
            }
            return url;
        }
        
        void ParseUrl(const std::string &url, std::string &host, std::string &path)
        {
            // 查找 URL 中的 "http://",并获取其后的部分
            size_t httpPos = url.find("http://");
            if (httpPos != std::string::npos)
            {
                std::string urlWithoutHttp = url.substr(httpPos + 7); // 7 是 "http://" 的长度
                // 查找 "/",分隔主机名和路径
                size_t slashPos = urlWithoutHttp.find('/');
                if (slashPos != std::string::npos)
                {
                    host = urlWithoutHttp.substr(0, slashPos);
                    path = urlWithoutHttp.substr(slashPos);
                }
                else
                {
                    // 如果没有找到 "/",则整个剩余部分都是主机名
                    host = urlWithoutHttp;
                    path = "/";
                }
            }
            else
            {
                // 如果没有 "http://" 前缀,则默认协议为 HTTP,整个 URL 都是主机名
                host = url;
                path = "/";
            }
    
            // Debug
            // std::cout << "url: " + url << std::endl;
            // std::cout << "host: " + host << std::endl;
            // std::cout << "path: " + path << std::endl;
    
        }
        int CreateServerSocket(const std::string &host)
        {
            // 域名解析
            addrinfo* result = NULL;
            addrinfo hints;
    
            ZeroMemory(&hints, sizeof(hints));
            hints.ai_family = AF_INET;  // 使用IPv4地址
            hints.ai_socktype = SOCK_STREAM;
    
            if (getaddrinfo(host.c_str(), "http", &hints, &result) != 0)
            {
                fprintf(stderr, "CreateServerSocket(): Failed to resolve the host: %s\n", host.c_str());
                return -1; // 返回-1表示连接失败
            }
    
            // 创建Socket
            int serverSocket = socket(AF_INET, SOCK_STREAM, 0);
            if (serverSocket == -1)
            {
                fprintf(stderr, "CreateServerSocket(): create socket error: %s(errno: %d)\n", strerror(errno), errno);
                freeaddrinfo(result);  // 释放内存
                return -1; // 返回-1表示连接失败
            }
    
            // 设置服务器地址信息
            struct sockaddr_in serverAddr;
            memset(&serverAddr, 0, sizeof(serverAddr));
            serverAddr.sin_family = AF_INET;
            serverAddr.sin_port = htons(80); // 设置端口号为80,可以根据需要修改
            serverAddr.sin_addr.s_addr = ((struct sockaddr_in *)(result->ai_addr))->sin_addr.s_addr;
    
            // 连接到原服务器
            if (connect(serverSocket, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) == -1)
            {
                fprintf(stderr, "CreateServerSocket(): connect error: %s(errno: %d)\n",strerror(errno),errno);
                closesocket(serverSocket); // 在Windows中使用closesocket关闭套接字
                freeaddrinfo(result);  // 释放内存
                return -1; // 返回-1表示连接失败
            }
            freeaddrinfo(result);  // 释放内存
            return serverSocket; // 返回连接成功的套接字描述符
        }
    
        bool ServerToClient(const std::string &url, int clientSocket)
        {
            // 解析URL,获取主机名和路径
            std::string host, path;
            ParseUrl(url, host, path);
    
            // 创建Socket连接到原服务器
            int serverSocket = CreateServerSocket(host);
            if (serverSocket == -1)
            {
                return FALSE; // 处理连接失败的情况
            }  
            // 构建HTTP请求
            std::string httpRequest = "GET " + path + " HTTP/1.1" + MY_CRLF + "Host: " + host + MY_CRLF + "Connection: close" + MY_CRLF;
    
            std::string date;
            bool sel;
    
            if (cache_.Check(url)) 
            {
                sel = false;
                date = cache_.GetDate(url);
                std::string cacheRequest = httpRequest + "If-Modified-Since: " + date + MY_CRLF + MY_CRLF;
                // 发送HTTP, 带有If-Modified-Since 首部行
                if (send(serverSocket, cacheRequest.c_str(), cacheRequest.size(), 0) == -1)
                {
                    perror("Error sending request to server");
                    closesocket(serverSocket);
                    return FALSE;
                }
                std::string cacheResponse;
                char cacheBuffer[HEADSIZE];
                ssize_t cacheBytesRead;
                cacheBytesRead = recv(serverSocket, cacheBuffer, HEADSIZE - 1, 0);
                std::string responseNotModified(cacheBuffer);
    
        
                // std::cout << "responseNotModified: " << responseNotModified << std::endl;
    
                if (IsResponseNotModified(responseNotModified) ) 
                {
                    // std::cout << "304 Not Modified" << std::endl;
                    sel = false;
                }else
                {
                    cache_.ClearFileContent(url); //清空
                    sel = true;
                }
    
            }else
            {
                sel = true;
            }
        
            if (sel == false) 
            {
    
                // std::cout << "cache hit!" << std::endl;
                // 接收缓存,转发到客户端
                char buffer[BUFSIZE];
                size_t start = 0;
                size_t bytesRead;
                while (1)
                {
                    if (cache_.Get(url, buffer, start, bytesRead) == false)
                    {
                        perror("Error sending response to client");
                    }
    
                    // std::cout << "bytesRead: " << bytesRead << std::endl;
                    if (bytesRead == 0) break;
    
                    if (send(clientSocket, buffer, bytesRead, 0) == -1)
                    {
                        perror("Error sending response to client");
                        closesocket(serverSocket);
                        return FALSE;
                    }
                }
               
            }else
            {
                httpRequest += MY_CRLF;
                // 发送HTTP请求到原服务器
                if (send(serverSocket, httpRequest.c_str(), httpRequest.size(), 0) == -1)
                {
                    perror("Error sending request to server");
                    closesocket(serverSocket);
                    return FALSE;
                }
    
                // 接收原服务器的HTTP响应
                char buffer[BUFSIZE];
                size_t start = 0;
                ssize_t bytesRead;
                while ((bytesRead = recv(serverSocket, buffer, BUFSIZE - 1, 0)) > 0)
                {
                    buffer[bytesRead] = '\0';
                    // 发送接收到的数据到客户端
                    if (send(clientSocket, buffer, bytesRead, 0) == -1)
                    {
                        perror("Error sending response to client");
                        closesocket(serverSocket);
                        return FALSE;
                    }
                    if(cache_.Put(url, buffer, bytesRead, start) == false)
                    {
                        std::cerr << "Cache put error" << std::endl;
                    }
                }
                cache_.PutDate(url);
                if (! cache_.Check(url))
                {
                    cache_.ClearFileContent(url);
                }
            }
            // 关闭原服务器连接
            closesocket(serverSocket);
            return TRUE;
        }
        bool IsResponseNotModified(const std::string& response) {
           // 查找第一个空格,定位到状态码的开始
            size_t spacePos = response.find(' ');
            if (spacePos != std::string::npos) {
                // 提取状态码部分
                std::string statusCode = response.substr(spacePos + 1, 3);
                // 检查状态码是否为 "304"
                return (statusCode == "304"); // HTTP/1.1 304 Not Modified
            }
            return false; // 未找到状态码
        }
    };
    
    
    
    bool InitWinsock()
    {
        // 加载套接字库(必须)
        WORD wVersionRequested;
        WSADATA wsaData;
        // 套接字加载时错误提示
        int err;
        // 版本 2.2
        wVersionRequested = MAKEWORD(2, 2);
        // 加载 dll 文件 Scoket 库
        err = WSAStartup(wVersionRequested, &wsaData);
        if (err != 0)
        {
            // 找不到 winsock.dll
            printf("加载 winsock 失败,错误代码为: %d\n", WSAGetLastError());
            return FALSE;
        }
        if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)
        {
            printf("不能找到正确的 winsock 版本\n");
            return FALSE;
        }
    
        return TRUE;
    }
    
    int main()
    {
        if (!InitWinsock())
        {
            WSACleanup();
            return -1; // 初始化失败,退出程序
        }
        int port = 666; // 设置端口
        HttpProxyServer proxyServer(port);
        proxyServer.Start();
        WSACleanup(); // 在程序结束时清理Winsock库
        return 0;
    }
    

    __EOF__

  • 本文作者: 江水为竭
  • 本文链接: https://www.cnblogs.com/Az1r/p/17952131
  • 关于博主: 评论和私信会在第一时间回复。或者直接私信我。
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
  • 声援博主: 如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。
  • 相关阅读:
    【逆向】Base64编码解码及逆向识别
    HTML+CSS篮球静态网页设计(web前端网页制作课作业)NBA杜兰特篮球运动网页
    python学习之路
    nexus 5X刷机并使用Magisk获取root权限
    春夏秋冬-第12届蓝桥杯Scratch选拔赛真题精选
    day13|二叉树理论
    在VmWare中安装Centos7
    Java毕设项目——校园出入管理系统(java+SSM+Maven+Mysql+Jsp)
    Java手写红黑树应用拓展案例
    JSON.parse()和JSON.stringify()的使用
  • 原文地址:https://www.cnblogs.com/Az1r/p/17952131