我很难开始使用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)
正如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调用者的选项.这可以用于分配管理缓冲区而不使用全局变量.我强烈建议你这样做.