HTTP Post
这一章介绍如何使用libcurl以Post方式向HTTP服务器提交数据。
方法一,也是最简单的方式,就像html中使用<form>标签提交数据一样,只需向libcurl提供一个包含数据的字符串即可。下面是笔者学习过程中的一个demo程序:
int main(int argc, char **argv)
{
code = curl_global_init(CURL_GLOBAL_WIN32);
CURL *easy_handle = curl_easy_init();
curl_easy_setopt(easy_handle, CURLOPT_URL, http://localhost:2210/Default.aspx);
// 单个域post
curl_easy_setopt(easy_handle, CURLOPT_POSTFIELDS, "name=jgood&address=hangzhou");
code = curl_easy_perform(easy_handle);
curl_easy_cleanup(easy_handle);
curl_global_cleanup();
return 0;
}
在asp.net Web服务器上跟踪调试,得到客户程序提交上来的数据,下面是截图:
上面的代码够简单吧~_~ 有时候,我们需要提交一些二进制数据到HTTP服务器,使用方法一就不行了,因为方法一中实际提交的是一个字符串,字符串遇到/0就表示结束了。所以在上传二进制数据的时候,必须明确的告诉libcurl要提交的数据的长度。在上传二进制数据的时候,还应该设置提交的Content-Type头信息。下面的示例代码:
int main(int argc, char **argv)
{
curl_global_init(CURL_GLOBAL_WIN32);
CURL *easy_handle = curl_easy_init();
// 上传二进制数据
char data[] = { 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0 };
curl_slist *http_headers = NULL;
http_headers = curl_slist_append(http_headers, "Content-Type: text/xml");
curl_easy_setopt(easy_handle, CURLOPT_HTTPHEADER, http_headers);
curl_easy_setopt(easy_handle, CURLOPT_URL, http://localhost:2210/Default.aspx);
curl_easy_setopt(easy_handle, CURLOPT_POSTFIELDS, data);
curl_easy_setopt(easy_handle, CURLOPT_POSTFIELDSIZE, sizeof(data));
curl_easy_perform(easy_handle);
curl_slist_free_all(http_headers);
curl_easy_cleanup(easy_handle);
curl_global_cleanup();
return 0;
}
在asp.net Web服务器上跟踪调试,得到客户程序提交上来的二进制数据,下面是截图:
上面介绍的两种方式,可以完成大部分的HTTP POST操作。但上面的两种方式都不支持multi-part formposts。Multi-part formposts被认为是提交二进制数据(或大量数据)的更好方法,可以在RFC1867, RFC2388中找到他们的定义。何为Multi-part?其实,就我理解,就是在Post提交的时候,有不同的数据单元,每个单元有自己的名称与内容,内容可以是文本的,也可以是二进制的。同时,每个数据单元都可以有自己的消息头,MIME类型,这些数据单元组成一个链表,提交到HTTP服务器。 libcurl提供了方便的api用于支持multi-part formposts。使用curl_formadd函数,可以添加不同的数据数据单元,然后提交到服务器。下面是一个multi-part formposts的例子
int main()
{
curl_global_init(CURL_GLOBAL_WIN32);
CURL *easy_handle = curl_easy_init();
// 使用multi-parts form post
curl_easy_setopt(easy_handle, CURLOPT_URL, http://localhost:2210/Default.aspx);
curl_httppost *post = NULL;
curl_httppost *last = NULL;
// 文本数据
curl_formadd(&post, &last, CURLFORM_COPYNAME, "name", CURLFORM_COPYCONTENTS, "JGood", CURLFORM_END);
curl_formadd(&post, &last, CURLFORM_COPYNAME, "address", CURLFORM_COPYCONTENTS, "HangZhou", CURLFORM_END);
// 文本文件中的数据
curl_formadd(&post, &last, CURLFORM_COPYNAME, "file", CURLFORM_FILECONTENT, "ReadMe.txt", CURLFORM_END);
curl_easy_setopt(easy_handle, CURLOPT_HTTPPOST, post);
curl_easy_perform(easy_handle);
curl_formfree(post);
curl_easy_cleanup(easy_handle);
curl_global_cleanup();
return 0;
}
最后要说明的是,所有在easy handle上设置的属性都是”sticky”的,什么意思?就是说在easy handle上设置的属性都将被保存,即使执行完curl_easy_perform之后,这些属性值仍然存在。通过将CURLOPT_HTTPGET设为1可以使easy handle回到最原始的状态:
curl_easy_setopt(easy_handle, CURLOPT_HTTPGET, 1L);
显示进度
libcurl支持通信过程中的进度控制。通过将CURLOPT_NOPROCESS设置为0开启进度支持。该选项默认值为1。对大多数应用程序,我们需要提供一个进度显示回调。libcurl会不定期的将当前传输的进度通过回调函数告诉你的程序。回调函数的原型如下:
int progress_callback(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow);
通过CURLOPT_PROGRESSFUNCTION注册该回调函数。参数clientp是一个用户自定义指针,应用程序通过 CURLOPT_PROCESSDATA属性将该自定义指定传递给libcurl。libcurl对该参数不作任何处理,只是简单将其传递给回调函数。
在C++中使用libcurl
在C++中使用libcurl跟在C语言中没有任何区别,只有一个地方要注意:回调函数不能是类的非静态成员函数。例如:
class AClass {
static size_t write_data(void *ptr, size_t size, size_t nmemb, void *ourpointer)
{
/* do what you want with the data */
}
}
文章出处:飞诺网(www.firnow.com):http://dev.firnow.com/course/3_program/c++/cppjs/20100603/207496_2.html