CURLOPT_WRITEDATA

时间:2016-10-05 10:44:44

标签: c++ json rest curl libcurl

我正在使用libcurl来使用来自网络服务器的GET请求来获取json数据。

这是我的示例代码:

char *DownloadedResponse;

static int writer(char *data, size_t size, size_t nmemb, char *buffer_in)
{
    if (buffer_in != NULL)  
    {
        buffer_in = new char[size*nmemb];
        strcpy(buffer_in,data);
        DownloadedResponse = buffer_in;

        return size * nmemb;  

    }

    return 0;

} 


char * DownloadJSON(string URL)
{   
    CURL *curl;
    CURLcode res;
    struct curl_slist *headers=NULL;

    curl_slist_append(headers, "Accept: application/json");  
    curl_slist_append( headers, "Content-Type: application/json");
    curl_slist_append( headers, "charsets: utf-8"); 
    curl = curl_easy_init();

    if (curl) 
    {
        curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
        curl_easy_setopt(curl, CURLOPT_URL, URL.c_str());
        curl_easy_setopt(curl, CURLOPT_HTTPGET,1); 
        curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); 
        curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,writer);

        res = curl_easy_perform(curl);

        if (CURLE_OK == res) 
        { 

            char *ct;         
            res = curl_easy_getinfo(curl, CURLINFO_CONTENT_TYPE, &ct);

            if((CURLE_OK == res) && ct)
            {
                cout<<"\nresponse received: "<<DownloadedResponse;

            }
            else
            {
                curl_slist_free_all(headers);
                curl_easy_cleanup(curl);
                curl = NULL;
                return NULL;
            }

        }
    }

    curl_slist_free_all(headers);
    curl_easy_cleanup(curl);
        curl = NULL;


}

在这里,我能够在CURLOPT_WRITEFUNCTION的回调“作家”中的DownloadedResponse中获取json数据。

但如果我使用CURLOPT_WRITEDATA的自定义指针打印,

char *dataPointer = NULL;
CURLcode curl_easy_setopt(curl, CURLOPT_WRITEDATA, dataPointer);
cout<<dataPointer;

dataPointer的输出为空。 这是什么问题,因为我能够在CURLOPT_WRITEFUNCTION的回调中打印json数据,而不是在CURLOPT_WRITEDATA

的指针中打印

1 个答案:

答案 0 :(得分:0)

您编写了一个从网络读取数据的函数,并将其写入您想要的位置。

static int writer(char *data, size_t size, size_t nmemb, char *buffer_in){
    if (buffer_in != NULL) { 
        // very bad code which is never executed
    }
    return 0;
} 

为了让该函数写入数据,它必须知道在哪里写它,所以你要告诉它写入NULL

char *dataPointer = NULL;
CURLcode curl_easy_setopt(curl, CURLOPT_WRITEDATA, dataPointer);

你告诉它作为buffer_in有什么价值?你传递dataPointer,它是NULL,所以你只告诉它buffer_in = NULL。我想你应该说&#34; dataPointer&#34;的地址,它将是&amp; dataPointer。

从技术上讲,我现在已经回答了你的问题。您为缓冲区传递了NULL,因此写入函数立即退出。但还有更多。现在你可以在writer()中执行非常糟糕的代码。

if (buffer_in != NULL)  
{
    // if buffer_in already has allocated memory then leak it immediately
    // create a new buffer of memory to leak later
    buffer_in = new char[size*nmemb];

    // store the data in buffer_in
    // assume it is null terminated (it is not)
    // rather than using the length we already know
    strcpy(buffer_in,data);

    // remember buffer_in? We don't use it so assign that data pointer to a global variable. 
    DownloadedResponse = buffer_in;

    // return size of this particular chunk of data
    return size * nmemb;  
}

此函数必须使用数据的长度,而不是假设数据以空值终止(参见https://curl.haxx.se/libcurl/c/CURLOPT_WRITEFUNCTION.html)。

这个函数必须能够通过将数据添加到它已经读取的内容来处理多个小块中的数据。您无法调用新内存,然后丢弃新内存。而且无论如何你都无法做到这一点,因为你只是泄露了那个记忆 - 每个新记忆必须与一次删除相匹配。事实上,我们建议你不要使用new或者删除,因为我们有标准的库。

此函数应使用您提供的buffer_in参数而不是全局变量,但如果需要,可以使用全局变量,它只是容易出错。它不是像其他东西那样的错误。

buffer_in的重点是为您提供一个持久的数据结构,您可以在其中累积答案。它可能应该在curl_easy_execute周围的本地范围内,因此如果你有CURLE_OK,那么你可以只返回该数据结构中的内容。我强烈建议您将数据写入std :: vector,这样您就不必跟踪内存分配。你有麻烦,但根本不需要这样做。现代风格说每个人都有麻烦,所以只需让标准库处理它。

您声称要按照文档中的示例进行操作,该文档链接到https://curl.haxx.se/libcurl/c/getinmemory.html如果再看一遍,您会看到他们正在做什么,以及您的代码如何匹配。特别是,它们传递&amp; chunk(块的地址)然后将数据写入块中,以便它们保留之前的内容。

struct MemoryStruct {
  char *memory;
  size_t size;
};

static size_t
WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp)
{
    // here is where they get access to the buffer
    struct MemoryStruct *mem = (struct MemoryStruct *)userp;

在curl调用中,您将找到本地定义的结构,然后是远程调用:

struct MemoryStruct chunk;
curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&chunk);
res = curl_easy_perform(curl_handle);
if (stuff)
    printf("%lu bytes retrieved\n", (long)chunk.size);