2016-07-01 6 views
0

Visual Studio 2013 Community로 Win64에서 개발하고 wxWidgets와 함께 Win64와 Linux 모두에 배포하십시오. 내가 libcurl에를 사용하여 C++ 다음과 같은 curl.exe 명령 줄을 모방하려고 :C++에서 libcurl로 게시하면 콜백 매개 변수가 쓰레기입니다.

curl.exe -X POST -g "single-url-string" 

이 최종 사용자가 자신의 장치를 제어 할 수있는 단일 URL 문자열을 공급하는 앱의의 IoT 기능입니다 . 이 논리가 curl.exe를 외부 프로세스로 실행하는 것이 아니라는 이유는이 논리가 자체 스레드에서 실행되고 wxWidgets가 주 스레드 외부에서 외부 실행 파일을 시작하는 것을 지원하지 않기 때문입니다.

일반적으로 curl.exe로 POST를 수행하는 경우 게시물 데이터가 옵션으로 제공됩니다. 이것은 curl.exe에게 주어진 url에 대한 POST 작업임을 알려주며 여기에 POST에 대한 데이터가 있습니다. 보시 다시 피, 내가 뭘하려는 GET 스타일 url (매개 변수를 url에 포함 된)하지만 다음 POST 작업 변경. 연구 결과에 따르면 최종 사용자에게 두 개의 별도 URL과 데이터 문자열을 제공하라는 요청이 단순히 너무 복잡하기 때문에 이러한 방식으로 완료되었습니다. 그래서 우리는이 쉬운 단일 문자열을 생각해 냈습니다. 최종 사용자는 반드시 문자열을 해석 할 필요없이 장치 설명서에서 문자열을 복사하기 만하면됩니다. 문자열을 별도의 의미있는 문자열로 나누는 것이 훨씬 간단합니다.

두 가지 버전의 간단한 C++ libcurl POST 루틴이 있지만 두 버전 모두 쓰기 콜백에 의해 수신 된 매개 변수가 잘못되었습니다. 두 버전은 단일 URL 문자열이있는 POST와 URL 문자열에 별도의 옵션으로 제공되는 게시물 데이터가있는 POST입니다.

문제는 1) 단일 문자열 버전을 사용하면 POST가 실행되지 않고 쓰기 콜백 매개 변수가 잘못되었습니다. 2) 두 문자열 버전을 사용하면 POST가 실행되지만 쓰기 콜백 매개 변수는 다른 방식으로 잘못되었습니다.

쓰기 콜백의 데이터 포인터 매개 변수는 두 버전 모두 메모리 주소 1을 가리키며 size 매개 변수는 두 버전 모두에서 잘 나타납니다. 그러나 nmemb 매개 변수는 거대한 임의 값 (단일 문자열 버전) 또는 0 (두 문자열 POST 버전).

여기 내 코드가 있습니다. 예, 앱 시작시 curl_global_init()을 호출합니다.

size_t CX_IOT_THREAD::curl_write_callback(char *ptr, size_t size, size_t nmemb, void *userdata) 
{ 
    // storage for transferred data: 
    const int dataStoreSize = CURL_MAX_WRITE_SIZE + 1; 
    char dataStore[dataStoreSize]; 
    memset(dataStore, 0, dataStoreSize); // zeroed out 

    size_t dataSize = size * nmemb; // bytes sent 

    if (dataSize) 
    { 
    memcpy(dataStore, ptr, dataSize); // copy into buffer sized so we'll have a terminating NULL char 

    wxString msg = wxString::Format(wxT("%s"), dataStore); // send as event, eventually to the log 
    mp_queue->Report(CX_IOTTHR_CMD_ACCESS_JOB, msg); 

    // must return byte count processed for libcurl to be happy: 
    return dataSize; /**/ 
    } 

return size; // should be dataSize, but because nmemb is bad, I’m using size; it works. 
} 

cx_int CX_IOT_THREAD::Post(std::string& url) 
{ 
    if (url.length() == 0) 
    return -1; 

    char errBuf[CURL_ERROR_SIZE]; 
    errBuf[0] = '\0'; 
    static const char *postthis = "name=Bloke&age=67"; 

    CURLcode ret; 
    CURL *hnd = curl_easy_init(); 
    curl_easy_setopt(hnd, CURLOPT_URL, url.c_str()); 
    curl_easy_setopt(hnd, CURLOPT_POSTFIELDS, postthis); 
    curl_easy_setopt(hnd, CURLOPT_POSTFIELDSIZE, (long)strlen(postthis)); 
    curl_easy_setopt(hnd, CURLOPT_ERRORBUFFER, errBuf); 
    curl_easy_setopt(hnd, CURLOPT_WRITEFUNCTION, &CX_IOT_THREAD::curl_write_callback); 
    curl_easy_setopt(hnd, CURLOPT_WRITEDATA, NULL); 
    curl_easy_setopt(hnd, CURLOPT_NOPROGRESS, 1L); 
    curl_easy_setopt(hnd, CURLOPT_USERAGENT, "curl/7.49.1"); 
    curl_easy_setopt(hnd, CURLOPT_MAXREDIRS, 50L); 
// curl_easy_setopt(hnd, CURLOPT_CUSTOMREQUEST, "POST"); 
    ret = curl_easy_perform(hnd); 
    curl_easy_cleanup(hnd); 

    if (ret != CURLE_OK) 
    { 
     wxString msg = wxString::Format(wxT("Attempted POST failed, libcurl return code '%d'."), (cx_int)ret); 
     mp_queue->Report(CX_IOTTHR_CMD_ACCESS_JOB, msg, (cx_int)ret); 

     cx_int len = strlen(errBuf); 
     if (len > 0) 
     msg = wxString::Format("%s%s", errBuf, ((errBuf[len - 1] != '\n') ? "\n" : "")); 
     else msg = wxString::Format("%s\n", curl_easy_strerror(ret)); 
     mp_queue->Report(CX_IOTTHR_CMD_ACCESS_JOB, msg, (cx_int)ret); 
    } 
    return (cx_int)ret; 
} 

쓰기 콜백 매개 변수가 잘못된 이유는 무엇입니까? 단일 문자열 버전이 게시물을 작성하지 않는 이유는 무엇입니까? (단일 문자열 버전은 위에서 설명한 2 개의 POSTFIELDS 옵션을 사용하고 CUSTOMREQUEST 옵션은 활성화되어 있습니다.)

+1

'curl_write_callback'은 비 정적 멤버 함수입니까? 그건 날지 않을거야. 정적 멤버 또는 자유 함수 여야합니다. 여러분이 보시는 것은 모든 매개 변수가 하나씩 넘어갔습니다 (여러분의 함수가'this'를 예상하고 컬이 그것을 통과하지 않기 때문에) : 1은'size'에 들어가야하고'size'에있는 좋은 값은'nmemb'에 들어갈 것입니다 . –

+0

@IgorTandetnik 그게 다야! 너는 오늘 나의 신이다. 고맙습니다! –

답변

0

Igor Tandetnik이 지적했듯이 콜백은 정적이어야합니다.

+0

또는 ... [콜백에 C++ 비 정적 함수 사용?] (https://curl.haxx.se/docs/faq.html#Using_C_non_static_functions_f) –