LibCurl是一个开源的免费的多协议数据传输开源库,该框架具备跨平台性,开源免费,并提供了包括HTTP
、FTP
、SMTP
、POP3
等协议的功能,使用libcurl
可以方便地进行网络数据传输操作,如发送HTTP
请求、下载文件、发送电子邮件等。它被广泛应用于各种网络应用开发中,特别是涉及到数据传输的场景。
官网:curl
下载安装:curl - Download
安装步骤
说明:在编译任何开源代码前可以先看看README, INSTALL等文件, 会提供如何编译的信息。在此教程中通过阅读README和GIT-INFO文 件可以得到很多编译安装信息。 在GIT-INFO 中很明显地说了执行: ./buildconf产生configure配置文件。
-
./buildconf(产生configure配置文件)
-
./configure --with-openssl (我是默认安装openssl的)
-
make
-
make install(默认库文件安装在/usr/local/lib 头文件安装在/usr/local/include --->安装要root权限)
libcurl库的API接口
(1)初始化curl句柄
CURL* curl = NULL;
curl = curl_easy_init();
(2)设置curl的url
curl_easy_setopt(curl, CURLOPT_URL, "http://127.0.0.1:9001/login");
(3)开启post请求开关
curl_easy_setopt(curl, CURLOPT_POST, true);
(4)添加post数据
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post_str);
(5)设定一个处理服务器响应的回调函数
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, deal_response);
(6)给回调函数传递一个形参
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &responseData);
(7)向服务器发送请求,等待服务器的响应
res = curl_easy_perform(curl);
测试用例(实现网页下载保存):
// 采用CURLOPT_WRITEFUNCTION 实现网页下载保存功能
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <curl/curl.h>
#include <curl/easy.h>
FILE *fp; //定义FILE类型指针
//这个函数是为了符合CURLOPT_WRITEFUNCTION而构造的,完成数据保存功能
size_t write_data(void *ptr, size_t size, size_t nmemb, void *stream)
{
int written = fwrite(ptr, size, nmemb, (FILE *)fp);
return written;
}
int main(int argc, char *argv[])
{
CURL *curl;
if (argc != 3)
{
fprintf(stderr, "usage: %s url filename\n", argv[0]);
exit(-1);
}
curl_global_init(CURL_GLOBAL_ALL);
curl = curl_easy_init();
curl_easy_setopt(curl, CURLOPT_URL, argv[1]);
if((fp = fopen(argv[2],"w")) == NULL)
{
curl_easy_cleanup(curl);
exit(1);
}
//CURLOPT_WRITEFUNCTION 将后继的动作交给write_data函数处理
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
curl_easy_perform(curl);
curl_easy_cleanup(curl);
exit(0);
}
编译运行:
该库的使用很简单,首先我们需要调用curl_easy_init()
函数对CURL
对象进行初始化,接着通过调用curl_easy_setopt()
并传入一个访问URL
链接,当访问成功后则可curl_easy_perform()
函数得到访问结果。
<1>调curl_global_init()接口进行全局初始化
一个进程只需调用一次。如果一次都未调用,curl_easy_init()接口内部会自动调curl_global_init(),因为curl_easy_init()并不是多线程安全,如果两个线程同时调用curl_easy_init(),会概率出现一个线程在没有全局初始化下就进行网络传输导致崩溃,于是强烈建议显示调用curl_global_init()进行libcurl库进行全局初始化。
<2>调curl_easy_init()接口分配一个网络传输对象
因为libcurl是以C语言接口形式提供,所以后续调用的接口都需要提供该接口返回的句柄。
<3>调curl_easy_init()接口分配一个网络传输对象
因为libcurl是以C语言接口形式提供,所以后续调用的接口都需要提供该接口返回的句柄。
curl_easy_setopt()
函数第二个参数可以使用多种类型的变量定义,我们可以通过传入不同的常量来定义请求头中的参数,
CURLOPT_VERBOSE | 设置值为1启用调试输出,此时要设置CURLOPT_DEBUGFUNCTION 调试输出函数,排查问题时使用。 |
CURLOPT_URL | 设置URL地址 |
CURLOPT_PUT | 设置HTTP请求方法为PUT,CURLOPT_POST设置HTTP请求方法为POST,要设置HTTP请求方法为DELETE或PATCH,就得用CURLOPT_CUSTOMREQUEST |
CURLOPT_POSTFIELDS | 设置HTTP请求body内容,CURLOPT_POSTFIELDSIZE设置body大小,如果body内容是以\0结尾,可以不指定body大小。 |
CURLOPT_HTTPHEADER | 设置HTTP头部,HTTP头部是用curl_slist结构的链表,curl_slist_append()添加HTTP头部,可以调多次添加多个头部,curl_slist_free_all()释放curl_slis对象。 |
CURLOPT_WRITEFUNCTION | 设置HTTP请求body的数据输出函数,同时可以指定CURLOPT_WRITEDATA作为输出函数的user_data,libcurl会透传user_data。 |
CURLOPT_TIMEOUT_MS | 设置网络请求总超时值,CURLOPT_CONNECTTIMEOUT_MS设置网络socket连接超时值。 |
CURLOPT_SSL_VERIFYPEER | 设置0时不校验服务端,HTTPS请求时如果本地没有服务端证书,需要设置为0。 |
官方api文档
libcurl - curl_easy_setopt()
<4>调curl_easy_getinfo()接口获取网络请求响应信息
它类似于curl_easy_setopt()接口,第2个参数指定获取项,第3个参数依第2个参数不同而不同,比较常用的是CURLINFO_RESPONSE_CODE,获取状态码。
<5>调curl_easy_cleanup()接口释放资源
<6>调curl_global_cleanup()接口释放全局资源
下面的demo代码介绍如何使用libcurl库进行HTTP GET和POST请求
#include <stdio.h>
#include <curl/curl.h>
#include <string>
size_t write_callback(char *ptr, size_t size, size_t nmemb, void *userdata)
{
((std::string*)userdata)->append(ptr, nmemb);
return nmemb;
}
int main(void)
{
curl_global_init(CURL_GLOBAL_DEFAULT);
CURL* curl = curl_easy_init();
if (curl)
{
curl_easy_setopt(curl, CURLOPT_URL, "https://www.baidu.com");
// no certificate, not verify server certificate
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
std::string response_data;
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_data);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
CURLcode res = curl_easy_perform(curl);
if (res != CURLE_OK)
{
fprintf(stderr, "curl_easy_perform() failed: %s\n",
curl_easy_strerror(res));
}
else
{
long response_code;
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
printf("response code %ld \n", response_code);
printf("response data : \n ");
printf(response_data.c_str());
}
curl_easy_cleanup(curl);
}
curl_global_cleanup();
return 0;
}
运行结果:
#include <stdio.h>
#include <curl/curl.h>
#include <string>
size_t write_callback(char *ptr, size_t size, size_t nmemb, void *userdata)
{
((std::string*)userdata)->append(ptr, nmemb);
return nmemb;
}
int main()
{
curl_global_init(CURL_GLOBAL_DEFAULT);
CURL* curl = curl_easy_init();
if (curl)
{
// set url
curl_easy_setopt(curl, CURLOPT_URL, "https://jsonplaceholder.typicode.com/posts");
// no certificate, not verify server certificate
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
// set http method
curl_easy_setopt(curl, CURLOPT_POST, 1);
// set header
struct curl_slist * slist = nullptr;
slist = curl_slist_append(slist, "Content-Type : application/json");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist);
// set body
std::string body = "{\
\"title\":\"libcurl post title\",\
\"body\" : \"libcurl post body\",\
\"userId\" : 1}";
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, body.c_str());
// set response callback to read response
std::string response_data;
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_data);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
CURLcode res = curl_easy_perform(curl);
if (res != CURLE_OK)
{
fprintf(stderr, "curl_easy_perform() failed: %s\n",
curl_easy_strerror(res));
}
else
{
// get response code
long response_code;
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
printf("response code %ld \n", response_code);
printf("response data : \n ");
printf("%s", response_data.c_str());
}
curl_slist_free_all(slist);
curl_easy_cleanup(curl);
}
curl_global_cleanup();
return 0;
}
运行结果: