在C ++中使用libcurl发布,写回调参数是垃圾

时间:2016-07-01 17:38:27

标签: c++ curl libcurl iot

使用Visual Studio 2013社区在Win64上进行开发,使用跨平台的wxWidgets部署到Win64和Linux。我试图使用libcurl:

使用C ++模拟以下curl.exe命令行
curl.exe -X POST -g "single-url-string"

这是针对应用的物联网功能,最终用户提供单网址字符串来控制其设备。这个逻辑不仅仅是将curl.exe作为外部进程执行的原因是因为这个逻辑在它自己的线程中运行,并且wxWidgets不支持在主线程之外启动外部可执行文件。

通常在使用curl.exe执行POST时,后期数据作为选项提供。这告诉curl.exe操作是对提供的URL的POST,这是该POST的数据。正如您所看到的,我正在尝试做的是一个GET样式的url(参数嵌入在url中),然后将操作更改为POST。它是这样做的,因为研究显示要求最终用户提供两个单独的URL和数据字符串对他们来说太复杂了。所以我们想出了最终用户必须提供的这个更容易的单字符串,这通常只是从他们的设备手册复制一个字符串而不必解释字符串,更不用说将它分成单独的有意义的字符串。

所以,手头的问题是:我有两个版本的简单C ++ libcurl POST例程,但在两个版本中,write回调接收的参数都很糟糕。这两个版本是一个带有单个url字符串的POST,以及一个POST,其中post数据作为url字符串的单独选项提供。

问题是1)使用单字符串版本不执行POST,并且它的写回调参数不好; 2)使用两个字符串版本确实执行POST,但写回调参数是不好的,以不同的方式。

写回调中的数据指针参数指向两个版本中的内存地址1,size参数在两个版本中都显示良好,但nmemb参数是一个巨大的随机值(单字符串版本)或零(两个字符串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 个答案:

答案 0 :(得分:1)

正如Igor Tandetnik所指出的那样,回调必须是静态的。