关于CURL获取网页,返回的网页内容大小一直变化的原因

本文详细分析了一个用于检测网页篡改的程序,在获取网页大小时遇到的问题。通过观察调试信息,发现网页内容实际上是被压缩的。通过对相关代码段的调整,确保不接收压缩过的网页内容,程序能够正确地获取完整网页,从而解决大小变化的误报问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近在维护一个检测网页篡改检测的程序代码,代码会判断网页内容的大小,如果大小发生很大的变化就会报警,程序是通过CURL来获取网页大小的,程序运行在windows7下,使用的是VS2008

下面贴的代码是获取网页信息的函数:

int NetHelper::GetWebPageInfo( CString strUrl, bool bIsWap, bool bJustHeader, int& nFileSize, string& strContent )
{
    strContent.clear();
    nFileSize =0;

    init_curl initcurl;
    CURL * curl = initcurl.get_curl();
    CURLcode curlres;

    //libcurl初始化失败
    if(!curl)
    {
        strContent = "curl初始化失败!";
        return -1;
    }

    // 在堆栈上分配内存供 W2A等函数使用
    USES_CONVERSION;

    // 设置URL
    curl_easy_setopt(curl, CURLOPT_URL, W2A(strUrl));

    // 如果是ssl网站,不对ssl网站的证书进行验证
    curl_easy_setopt(curl,CURLOPT_SSL_VERIFYPEER,0);
    curl_easy_setopt(curl,CURLOPT_SSL_VERIFYHOST,0);

    curl_easy_setopt(curl,CURLOPT_COOKIEJAR,"e:\\cookie.txt");
    curl_easy_setopt(curl,CURLOPT_COOKIEFILE,"e:\\cookie.txt");

    // 超时设置
    curl_easy_setopt(curl,CURLOPT_TIMEOUT,10);

    if ( !bJustHeader )
    {
        // 设置读取HTTP返回内容的回调函数
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
        // 设置回调函数的参数,见write_callback函数的最后一个参数
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, &strContent);
    }//end if  
    else
    {
        // 设置读取HTTP头部内容的回调函数
        curl_easy_setopt(curl,CURLOPT_HEADERFUNCTION,header_callback);
        // 设置回调函数的参数,见header_callback函数的最后一个参数, 如果没有用到,
        curl_easy_setopt(curl, CURLOPT_HEADERDATA, &strContent);
        curl_easy_setopt( curl, CURLOPT_NOBODY, 1 );
    }


    // 自动转向
    curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);

    // 设置头
    curl_slist *chunk = NULL;
    chunk = curl_slist_append( chunk, "Accept: text/html, application/xhtml+xml, */*" ); 
    chunk = curl_slist_append( chunk, "Accept-Language: zh-CN" ); 
    if ( bIsWap )
    {
        chunk = curl_slist_append( chunk, "User-Agent: Mozilla/5.0 (Linux; U; Android 2.3.4; zh-cn; GT-I9100 Build/GINGERBREAD) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1" ); 
    } //end if
    else
    {
        chunk = curl_slist_append( chunk, "User-Agent: Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.7 (KHTML, like Gecko)" ); 
    }
    chunk = curl_slist_append( chunk, "Accept-Encoding: gzip, deflate" ); 
    chunk = curl_slist_append( chunk, "Connection: Keep-Alive" );
    curl_easy_setopt( curl, CURLOPT_HTTPHEADER, chunk );

    strContent.clear();
    curlres = curl_easy_perform(curl);

    long nStatus;

    if( curlres == CURLE_OK )
    {
        //服务器返回码
        curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &nStatus);
        nFileSize = strContent.size();
    }
    else
    {
        nStatus = curlres;
    }

    return nStatus;
}

情况是这样的,当我调试这个程序,检测网站,请求网页的时候,我用httpdebug抓包,获取的网页的Body大小是96354,我查看了内容,里面是完整的网页,这说明程序设置的url请求是没有错误的,每次都可以返回正确的网页,状态码Status是200.
这里写图片描述

然后我下断点查看nFileSize(表示网页内容大小的变量)情况是这样的:
这里写图片描述
这里写图片描述
这里写图片描述
大小是变化的,只有98666可以看到是完整的网页内容,其它都是“?”。

最后找出来的原因是:网页是被压缩了,把下图中的语句注释掉,服务器就不会返回压缩过的网页。这样每次获取的网页内容都是正常的了,大小都是98666。
这里写图片描述

### 回答1: 如何在Linux C中获取HTTP资源: 1. 首先需要创建一个TCP socket连接,使用socket()函数创建一个套接字,然后调用connect()函数连接到HTTP服务器,指定服务器的IP地址和端口号。 2. 读取HTTP响应:发送HTTP请求后,使用read()或recv()函数读取HTTP响应。HTTP响应的构成通常包含响应状态码、响应头和响应体。我们需要解析响应头,获取Content-Type和Content-Length等信息。 3. 解析HTTP响应:通常会使用正则表达式或字符串截取来解析HTTP响应头。需要注意的是,HTTP响应的结构可以随时更改,因此应该编写健壮的代码以适应变化。 4. 下载资源:根据Content-Length和Content-Type的信息,可以推断出需要下载的资源大小和类型。使用read()或recv()函数从HTTP服务器读取响应体,并将数据写入磁盘文件中。 5. 关闭连接:需要使用close()函数关闭TCP socket连接。 编写模板: 一个典型的HTTP请求流程可以用以下伪代码描述: 1. 创建TCP socket连接,连接到HTTP服务器 2. 组织HTTP请求,发送HTTP请求 3. 读取HTTP响应头,解析响应头,获取资源类型和大小 4. 读取响应体,将响应体存储到本地文件中 5. 关闭TCP socket连接 具体实现将涉及到如何使用Linux C中的套接字和Socket API,如何解析HTTP响应头和响应体等。可以借助第三方库来简化任务,如curl和libcurl。 ### 回答2: 获取http资源是许多网络应用程序的基础功能之一。在Linux系统下使用C语言编写获取http资源的程序,可以通过以下步骤实现: 1. 引入头文件 #include <stdio.h> // 标准输入输出头文件 #include <stdlib.h> // 标准库头文件 #include <string.h> // 字符串操作头文件 #include <netdb.h> // 网络数据头文件 #include <sys/socket.h> // 套接字头文件 #include <netinet/in.h> // IPV4协议头文件 2. 创建套接字 int sockfd; struct sockaddr_in servaddr; sockfd = socket(AF_INET, SOCK_STREAM, 0); 3. 设置服务器信息 memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(port); inet_pton(AF_INET, servip, &servaddr.sin_addr); 4. 连接服务器 connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)); 5. 发送http请求 char *request = "GET / HTTP/1.1\r\nHost: www.showapi.com\r\n\r\n"; send(sockfd, request, strlen(request), 0); 6. 接受http响应 char buffer[1024]; memset(buffer, 0, sizeof(buffer)); recv(sockfd, buffer, sizeof(buffer), 0); 7. 处理响应数据 可以通过字符串函数处理响应数据,如strstr、strtok等函数。 8. 关闭套接字 close(sockfd); 以上是获取http资源的基本流程,在实际应用中可以根据需要进行拓展和优化。一些更高级的功能,如https访问、多线程、异步回调等,可以通过使用一些专业的网络库或框架来实现。 ### 回答3: 在 Linux 平台下使用 C 语言获取 HTTP 资源需要用到网络编程相关的知识和 API。以下是一个简单的获取 HTTP 资源的模板: 1. 包含相关头文件 ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <netdb.h> #include <netinet/in.h> #include <netinet/tcp.h> #include <arpa/inet.h> #include <unistd.h> #include <fcntl.h> #include <sys/socket.h> #include <sys/types.h> ``` 2. 定义连接服务器的函数 ```c int conn_server(char* hostname, char* port) { struct addrinfo hints, *res; int sockfd, status; // 使用 getaddrinfo 获取服务器 IP 地址和相关信息 memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; if ((status = getaddrinfo(hostname, port, &hints, &res)) != 0) { perror("getaddrinfo error"); exit(1); } // 创建 socket 连接 sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (sockfd < 0) { perror("socket error"); exit(1); } // 使用 connect 函数连接服务器 if (connect(sockfd, res->ai_addr, res->ai_addrlen) < 0) { perror("connect error"); exit(1); } freeaddrinfo(res); return sockfd; } ``` 3. 发送 HTTP 请求报文给服务器 ```c void send_request(int sockfd, char* hostname, char* path) { char msg[1024]; sprintf(msg, "GET /%s HTTP/1.1\r\nHost: %s\r\n\r\n", path, hostname); write(sockfd, msg, strlen(msg)); } ``` 4. 接收服务器响应并输出 ```c void recv_response(int sockfd) { char buffer[1024]; int count; // 不断从 socket 中读取数据,直到读完 while ((count = read(sockfd, buffer, sizeof(buffer))) > 0) { fwrite(buffer, sizeof(char), count, stdout); } } ``` 5. 主函数中调用以上三个函数 ```c int main(int argc, char *argv[]) { int sockfd; char *hostname, *path, *port; if (argc < 4) { fprintf(stderr, "Usage: %s <hostname> <port> <path>\n", argv[0]); exit(1); } hostname = argv[1]; port = argv[2]; path = argv[3]; sockfd = conn_server(hostname, port); send_request(sockfd, hostname, path); recv_response(sockfd); // 关闭 socket 连接 close(sockfd); return 0; } ``` 参考以上模板,可以编写出获取 HTTP 资源的基本程序。需要注意的是,在实际开发中还需要处理异常情况,比如连接超时、服务器返回错误码、接收数据过程中的中断等等。另外,如果要实现 HTTPS 请求,则需要使用 SSL 进行加密和认证。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值