使用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启用了一个。)
答案 0 :(得分:1)
正如Igor Tandetnik所指出的那样,回调必须是静态的。