我在使用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/