2016-10-05 1 views
0

웹 서버에서 GET 요청을 사용하여 json 데이터를 가져 오는 데 libcurl을 사용하고 있습니다. 여기CURLOPT_WRITEDATA 문제

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의 사용자 정의 포인터를 사용하여 인쇄하는 경우, dataPointer의

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

출력은 비어 있습니다. 내가 할 수 당신은 네트워크에서 읽은 데이터를 소요하고 당신이 그것을 원하는 위치에 기록 함수를 작성 CURLOPT_WRITEDATA

+0

가 확실하지 난 당신이 뭘 하려는지 이해합니다. 'CURLOPT_WRITEDATA'는'WRITEFUNCTION' 콜백 ('bufer_in'라고 부름)에 대한 인자를 설정합니다. WRITEDATA 옵션을 설정했는지 여부에 관계없이 읽기 데이터는 여전히'data' 인수로 이동합니다. 이것이 귀하의 질문에 답변이되지 않는 경우, 전체 소스 (귀하가 WRITEDATA를 사용하는 곳)를 제공해주십시오. –

+0

@AndreyTurkin : 데이터 인수로 데이터를 가져올 수 있습니다. 내 요점은 URLcode curl_easy_setopt (컬, CURLOPT_WRITEDATA, dataPointer)를 사용하는 경우입니다; dataPointer가 json 데이터가있는 callback의 buffer_in을 가리키고 있기 때문입니다. buffer_in이 인쇄되면 json 데이터가 출력됩니다. 하지만 buffer_in이 비어있는 것을 가리키는 dataPointer를 인쇄하고 있습니다. – Satish

+0

코드 스 니펫 (snippet)은 curl_easy_setopt를 호출 한 직후 dataPointer에서 마술처럼 결과를 얻으 려한다고 예상 한 것처럼 보였습니다. 분명히 발생할 수는 없습니다. 자,이 전화로 달성하고자하는 것을 정확히 설명해 주시겠습니까? –

답변

0

의 포인터 CURLOPT_WRITEFUNCTION의 콜백에서 JSON 데이터를 인쇄하지만 할 수 있기 때문에 문제가 여기에 무엇. 당신은 당신이로 사용하도록 알 수 있습니까 어떤 가치

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

을 NULL로 작성을 말할 수 있도록 데이터를 작성하는 기능을 위해서는

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; 
} 

, 그것은 그것을 작성하는 곳을 알고있다 buffer_in? 당신은 그것을 dataPointer에 넘겨 주는데, 이것은 buffer_in = NULL이라고 말한 것입니다. 대신 당신이 "dataPointer의 주소"라고 말하려는 것 같아요, & dataPointer가 될 것입니다.

기술적으로 지금 귀하의 질문에 답변했습니다. 버퍼에 NULL을 전달하여 쓰기 함수가 즉시 종료되었습니다. 그러나 더 많은 것이 있습니다. 이제 작가()의 나쁜 코드를 실행하게됩니다.

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에 링크 된 문서의 예를 따르는 것으로 다시 한 번 살펴보면 현재 수행중인 작업과 코드가 일치하지 않는 작업이 표시됩니다. 특히 그들은 & 청크 (청크의 주소)를 전달한 다음 청크에 데이터를 기록하여 이전에 있었던 것을 유지합니다.전화에서

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; 

는 컬하는 당신은 구조체 로컬 후 원격 호출을 정의 찾을 :

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);