概念
http通信的优点很多,当然也有局限性。一般我们开发使用restful形式提供接口,这样可以完成RPC远程调用。
https = http + ssl
ssl是一种安全的传输层协议。通信前先建立安全通道,之后在传递数据。
libcurl库,一个c写的http库,想要支持ssl,编译时需要加入编译选项。
编译库
编译windows版的dll 链接
linux版本的library :编译时加入 ./configure --with-ssl 即可
windows dll已经编译好的库 https://download.csdn.net/download/u013919153/10848458 可下载
编程介绍
简单同步编程 (easy mode)
使用流程(套路)
1. 调用curl_global_init()初始化libcurl
2. 调用curl_easy_init()函数得到 easy interface型指针
3. 调用curl_easy_setopt()设置传输选项
4. 根据curl_easy_setopt()设置的传输选项,实现回调函数以完成用户特定任务
5. 调用curl_easy_perform()函数完成传输任务,返回码
6. 调用curl_easy_cleanup()释放内存
7. 调用curl_global_cleanup() (可以不用调用)
在整过过程中设置curl_easy_setopt()参数是最关键的,了解相关参数及对应作用很重要
重要函数介绍
1.CURLcode curl_global_init(long flags);
描述:
这个函数只能用一次。(其实在调用curl_global_cleanup 函数后仍然可再用)
如果这个函数在curl_easy_init函数调用时还没调用,它讲由libcurl库自动调用,所以多线程下最好主动调用该函数以防止在线程中curl_easy_init时多次调用。
注意:虽然libcurl是线程安全的,但curl_global_init是不能保证线程安全的,所以不要在每个线程中都调用curl_global_init,应该将该函数的调用放在主线程中。
参数:flags
CURL_GLOBAL_ALL //初始化所有的可能的调用。(常用)
CURL_GLOBAL_SSL //初始化支持 安全套接字层。
CURL_GLOBAL_WIN32 //初始化win32套接字库。
CURL_GLOBAL_NOTHING //没有额外的初始化。
2.void curl_global_cleanup(void);
描述:
在结束libcurl使用的时候,用来对curl_global_init做的工作清理。类似于close的函数。
注意:虽然libcurl是线程安全的,但curl_global_cleanup是不能保证线程安全的,所以不要在每个线程中都调用curl_global_init,应该将该函数的调用放在主线程中。
3.char *curl_version( );
描述: 打印当前libcurl库的版本。
4.CURL *curl_easy_init( );
描述:
curl_easy_init用来初始化一个CURL的指针(有些像返回FILE类型的指针一样). 相应的在调用结束时要用curl_easy_cleanup函数清理. 一般curl_easy_init意味着一个会话的开始. 它会返回一个easy_handle(CURL*对象), 一般都用在easy系列的函数中.
5.void curl_easy_cleanup(CURL *handle);
描述:
这个调用用来结束一个会话.与curl_easy_init配合着用.
参数:
CURL类型的指针.
6.CURLcode curl_easy_setopt(CURL *handle, CURLoption option, parameter);
描述:
这个函数最重要了.几乎所有的curl 程序都要频繁的使用它.它告诉curl库.程序将有如何的行为. 比如要查看一个网页的html代码等.(这个函数有些像ioctl函数)
参数:
1 CURL类型的指针
2 各种CURLoption类型的选项.(都在curl.h库里有定义,https://curl.haxx.se/libcurl/c/curl_easy_setopt.html)
3 parameter 这个参数 既可以是个函数的指针,也可以是某个对象的指针,也可以是个long型的变量.它用什么这取决于第二个参数.
CURLoption 这个参数的取值很多.具体的可以查看man手册.
7.CURLcode curl_easy_perform(CURL *handle);
描述:
这个函数在初始化CURL类型的指针 以及curl_easy_setopt完成后调用. 就像字面的意思所说perform就像是个舞台.让我们设置的option 运作起来.
参数:
CURL类型的指针.
8.消息头设置
struct curl_slist *headers=NULL; /* init to NULL is important */
headers = curl_slist_append(headers, "Hey-server-hey: how are you?");
headers = curl_slist_append(headers, "X-silly-content: yes");
/* pass our list of custom made headers */
curl_easy_setopt(easyhandle, CURLOPT_HTTPHEADER, headers);
curl_easy_perform(easyhandle); /* transfer http */
curl_slist_free_all(headers); /* free the header list */
如果修改已经存在的消息头,直接设置即可;如果删除消息头信息,直接设置对应内容为空即可。
发送http消息后,服务器会返回消息头,如果只是查看消息头内容,使用如下函数
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, 打印函数)
如果想获取特定信息,使用如下方法:
CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ... );
最后一个参数是接收变量。具体详情查看官网API
下面是完整通信设置代码
//http回调写函数
static size_t CurlWriteBuffer(char *buffer, size_t size, size_t nmemb, std::string* stream)
{
//第二个参数为每个数据的大小,第三个为数据个数,最后一个为接收变量
size_t sizes = size*nmemb;
if(stream == NULL)
return 0;
stream->append(buffer,sizes);
return sizes;
}
//http发送封装
int CPrinterDlg::posturl(std::string& msg, std::string& url, bool IsSSL)
{
CURL* pCurl=NULL; //一个libcurl的handle
CURLcode res; //返回状态码
std::string response; //返回信息
curl_global_init(CURL_GLOBAL_ALL); //全局初始化
pCurl = curl_easy_init(); //创建一个handle
//设置请求头
struct curl_slist* header_ = NULL;
header_ = curl_slist_append(header_,"Content-Type: application/json;charset=utf-8");
//添加请求头到handle
curl_easy_setopt(pCurl, CURLOPT_HTTPHEADER, header_);
//设置URL
curl_easy_setopt(pCurl, CURLOPT_URL, url.c_str());
////CURLOPT_WRITEFUNCTION 将后继的动作交给write_data函数处理
curl_easy_setopt(pCurl,CURLOPT_POSTFIELDS,msg.c_str()); //post请求消息数据
curl_easy_setopt(pCurl,CURLOPT_POSTFIELDSIZE,msg.length()); //消息长度
curl_easy_setopt(pCurl, CURLOPT_WRITEFUNCTION, CurlWriteBuffer); //回调函数
curl_easy_setopt(pCurl,CURLOPT_WRITEDATA,&response); //数据接收变量
curl_easy_setopt(pCurl,CURLOPT_TIMEOUT,m_settinginfo.m_http_timeout); //连接超时时间
//不支持ssl验证
if(m_settinginfo.m_ssl == 0)
{
curl_easy_setopt(pCurl, CURLOPT_SSL_VERIFYPEER, 0);//设定为不验证证书和HOST
curl_easy_setopt(pCurl, CURLOPT_SSL_VERIFYHOST, 0);
}
else
{
// 配置 https 请求所需证书
if (m_settinginfo.m_ssl == 1) //ssl单向验证,不验证服务器
{
curl_easy_setopt(pCurl, CURLOPT_SSL_VERIFYPEER, 0L);
}else
{//双向验证
curl_easy_setopt(pCurl, CURLOPT_SSL_VERIFYPEER, 1L);
curl_easy_setopt(pCurl, CURLOPT_SSL_VERIFYHOST, 0);
curl_easy_setopt(pCurl,CURLOPT_CAINFO,ca_info.ca_path.c_str());
}
//设置客户端信息
curl_easy_setopt(pCurl, CURLOPT_SSLCERT, ca_info.client_cert_path.c_str());
curl_easy_setopt(pCurl,CURLOPT_SSLCERTTYPE,"PEM");
curl_easy_setopt(pCurl, CURLOPT_SSLKEY, ca_info.client_key_path.c_str());
curl_easy_setopt(pCurl,CURLOPT_SSLKEYTYPE,"PEM");
//如果客户端证书密钥使用密码加密,设置加密密码
//curl_easy_setopt(pCurl, CURLOPT_KEYPASSWD, "your_key_password");
}
//执行http连接
res = curl_easy_perform(pCurl);
//清除消息头
curl_slist_free_all(header_);
//清除handle
curl_easy_cleanup(pCurl);
return 0;
}
更多信息查看网址:https://curl.haxx.se/libcurl/c/ libcurl库官网
参考网址:
https://www.cnblogs.com/lifan3a/articles/7479256.html
https://www.cnblogs.com/yongpan/p/8084854.html
https://www.cnblogs.com/cposture/p/9029014.html#_lab2_2_0