libcurl是优秀的C语言版http 库,时间比较久,目前支持也比较完善,官方网页见 https://curl.haxx.se/libcurl/
对很多协议都有很好的支持。
别的语言都有对http较完善的库支持, 在C/C++领域Libcurl可能是最好用的了吧。我本来是打算用Qt里面的Qnetworkmanager,无奈实在是太难用,这一点qt做的实在不怎么的。
一、编译
只说Windows下编译(32位)
官方下载源码,找到winbuild目录。打开vs2013开发人员命令提示工具,编译debug版本:
nmake /f Makefile.vc mode=static VC=12 DEBUG=yes
编译relase版本设置DEBUG=no就可以了; 生成两个文件:
在builds目录下找到生成的include和lib目录用来进行程序开发;在Windows下,debug版与release版不能通用。
libcurl_a_debug.lib
libcurl_a.lib
二、工程设置
分别将include目录和lib引入工程,windows平台下qt 的.pro文件是这样写的:
curl头文件放在include/curl目录下。debug和release用的curl的库不是同一个,否则会在运行时出错。
INCLUDEPATH += \
$$PWD/include \
win32{
Release:LIBS +=-L$$PWD/lib -llibcurl_a
Debug:LIBS+=-L$$PWD/lib -llibcurl_a_debug
}
三、写代码
1.引入头文件
用静态链接方式的话,必须定义这个宏。
#define CURL_STATICLIB //静态链接
#include <curl/curl.h>
2.主要流程
curl_easy_init();进行初始化操作
curl_easy_setopt(curl, A, Value); 这个函数用于设置http各个参数
CURLOPT_DEBUGFUNCTION 指定调试输出时调用的函数。这里是OnDebug。具体可以参照 https://blog.csdn.net/mao834099514/article/details/54947853 中的例子。
CURLcode res;
CURL* curl = curl_easy_init();
if (NULL == curl)
{
return CURLE_FAILED_INIT;
}
if ( false )//用于调试的设置
{
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, OnDebug);
}
curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str());
curl_easy_setopt(curl, CURLOPT_POST, 1);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, strPost.c_str());
curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, OnWriteData);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&strResponse);
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT_MS, 3000);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 300);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1); //支持服务器跳转
curl_easy_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1L); // enable TCP keep-alive for this transfer
curl_easy_setopt(curl, CURLOPT_TCP_KEEPIDLE, 120L); // keep-alive idle time to 120 seconds
curl_easy_setopt(curl, CURLOPT_TCP_KEEPINTVL, 60L); // interval time between keep-alive probes: 60 seconds
struct curl_slist* headers = NULL;
headers = curl_slist_append(headers, "Content-Type:application/json;charset=UTF-8");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_POST, 1);//设置为非0表示本次操作为POST
res = curl_easy_perform(curl);
//curl_easy_cleanup(curl);
return res;
3.注意要点
一是上传json需要 在http头中加入"Content-Type:application/json;charset=UTF-8"
可以用curl_easy_setopt()函数实现。
二是如果需要保持长连接,需要CURLOPT_TIMEOUT 的设置一定要大于CURLOPT_TCP_KEEPIDLE的设置,或者设置为默认值0(不超时), 否则可能你还没等到应答就已经超时了。
参考:https://blog.csdn.net/sgiwxyg/article/details/45875081
三是 curl_easy_cleanup(curl); 会释放资源,如果释放后再curl_easy_init();发送数据会重新进行连接,
因此不要执行 curl_easy_cleanup(curl); 下一次发送数据时,才可以重用连接。
四是用好OnDebug函数,可以调试http发送过程。
OnDebug函数和OnWriteData函数如下:
static int OnDebug(CURL *, curl_infotype itype, char * pData, size_t size, void *)
{
if(itype == CURLINFO_TEXT)
{
//printf("[TEXT]%s\n", pData);
}
else if(itype == CURLINFO_HEADER_IN)
{
printf("[HEADER_IN]%s\n", pData);
}
else if(itype == CURLINFO_HEADER_OUT)
{
printf("[HEADER_OUT]%s\n", pData);
}
else if(itype == CURLINFO_DATA_IN)
{
printf("[DATA_IN]%s\n", pData);
}
else if(itype == CURLINFO_DATA_OUT)
{
printf("[DATA_OUT]%s\n", pData);
}
return 0;
}
static size_t OnWriteData(void* buffer, size_t size, size_t nmemb, void* lpVoid)
{
std::string* str = dynamic_cast<std::string*>((std::string *)lpVoid);
if( NULL == str || NULL == buffer )
{
return -1;
}
char* pData = (char*)buffer;
str->append(pData, size * nmemb);
return nmemb;
}
参考:https://blog.csdn.net/mao834099514/article/details/54947853 调试代码是从这拿过来的。