我在使用libcurl时遇到困难。以下代码似乎无法从指定的URL检索整个页面。我要去哪里错了?

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <curl/curl.h>
#include <curl/types.h>
#include <curl/easy.h>

using namespace std;

char buffer[1024];

size_t tobuffer(char *ptr, size_t size, size_t nmemb, void *stream)
{
    strncpy(buffer,ptr,size*nmemb);
    return size*nmemb;
}

int main() {
    CURL *curl;
    CURLcode res;


    curl = curl_easy_init();
    if(curl) {
        curl_easy_setopt(curl, CURLOPT_URL, "http://google.co.in");
        curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION,1);
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &tobuffer);

        res = curl_easy_perform(curl);

        printf("%s",buffer);

        curl_easy_cleanup(curl);
    }
    return 0;
}

最佳答案

at the libcurl documentation for curl_easy_setopt() 所示,回调函数被调用多次,以传递所提取页面的所有字节。

您的函数在每次调用时都会覆盖相同的缓冲区,结果是在curl_easy_perform()完成获取文件之后,您只剩下最后一次调用tobuffer()的条件。

简而言之,您的函数tobuffer()必须执行其他操作,而不是在每次调用时覆盖相同的缓冲区。

更新

例如,您可以执行以下完全未经测试的代码:

struct buf {
    char *buffer;
    size_t bufferlen;
    size_t writepos;
} buffer = {0};

size_t tobuffer(char *ptr, size_t size, size_t nmemb, void *stream)
{
    size_t nbytes = size*nmemb;
    if (!buffer.buffer) {
        buffer.buffer = malloc(1024);
        buffer.bufferlen = 1024;
        buffer.writepos = 0;
    }
    if (buffer.writepos + nbytes < buffer.bufferlen) {
        buffer.bufferlen = 2 * buffer.bufferlen;
        buffer.buffer = realloc(buffer, buffer.bufferlen);
    }
    assert(buffer.buffer != NULL);
    memcpy(buffer.buffer+buffer.writepos,ptr,nbytes);
    return nbytes;
}

在以后的程序中,您将需要释放分配的内存,如下所示:
void freebuffer(struct buf *b) {
    free(b->buffer);
    b->buffer = NULL;
    b->bufferlen = 0;
    b->writepos = 0;
}

另外,请注意,我使用memcpy()而不是strncpy()将数据移动到缓冲区。这一点很重要,因为libcurl不会声称传递给回调函数的数据实际上是NUL终止的ASCII字符串。特别是,如果检索.gif图像文件,则它肯定可以(并且将)包含要保存在缓冲区中的文件中的零字节。 strncpy()将在源数据中看到第一个NUL之后停止复制。

作为读者的练习,我将所有错误处理都留在了这段代码之外。您必须放一些。此外,由于无法调用realloc(),我也陷入了多汁的内存泄漏。

另一个改进将是使用允许回调的stream参数值来自libcurl调用程序的选项。这可以用来分配管理缓冲区而不使用全局变量。我强烈建议您也这样做。

关于c++ - 使用libcurl时出现问题:它似乎无法获取整个页面,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/3573146/

10-13 06:50