使用libcurl的问题:它似乎没有获得整个页面

raj*_*raj 1 c c++ libcurl

我很难开始使用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;
}
Run Code Online (Sandbox Code Playgroud)

RBe*_*eig 6

正如libcurl文档中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;
}
Run Code Online (Sandbox Code Playgroud)

在程序的某个稍后阶段,您将需要释放分配的内存,如下所示:

void freebuffer(struct buf *b) {
    free(b->buffer);
    b->buffer = NULL;
    b->bufferlen = 0;
    b->writepos = 0;
}
Run Code Online (Sandbox Code Playgroud)

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

作为读者的练习,我已将所有错误处理留在此代码之外.你必须放入一些.此外,我还留下了一个多汁的内存泄漏,因为呼叫realloc()失败的可能性很大.

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