libcurl支持http、https、ftp、gopher、telnet、dict、file和ldap协议。libcurl同时也支持HTTPS认证、HTTP POST、HTTP PUT、 FTP 上传(这个也能通过PHP的FTP扩展完成)、HTTP 基于表单的上传、代理、cookies和用户名+密码的认证。本文通过一个示例Demo介绍通过libcurl实现https访问服务器。
对libcurl 库的封装类示例如下,
#pragma once
#include "stdafx.h"
#include
#include
#include "curl/include/curl.h"
#include "curl/include/easy.h"
#pragma comment(lib,"curl/lib/libcurl.lib")
/************************************************************************/
/* libcurl库封装 sh 2019年7月32日 13:17:11 */
/************************************************************************/
//表单key对应的类型
enum E_KEY_TYPE {
e_key_text, //文本类型
e_key_iamge //图片类型
};
//表单信息结构
typedef struct
{
std::string strKey;
std::string strVal;
E_KEY_TYPE eKeyType;
void Set(std::string key, std::string val, E_KEY_TYPE eType)
{
strKey = key;
strVal = val;
eKeyType = eType;
}
}POST_LIST, *LPPOST_LIST;
//表单数据
#define _POST_LIST_DATA_ std::vector
class CTools
{
public:
static std::string replace(const char *pszSrc, const char *pszOld, const char *pszNew);
static const char * getAppPath();
};
class CUrlHttp
{
public:
CUrlHttp(void);
~CUrlHttp(void);
static int Request(std::string strRequestType,
std::string strUrl,
std::string &strReport,
std::vector vecHeader,
std::string strParam="",
std::string strCookie="",
std::string strCaPath="",
int nTimeOut=0);
//有图片建议使用表单提交比较方便
static int RequestSSL(std::string strUrl,
std::string &strReport,
_POST_LIST_DATA_ listParam,
std::vector vecHeader,
std::string strCookie="",
std::string strCaPath="",
int nTimeOut=0);
};
class CUrlFtp
{
public:
CUrlFtp();
~CUrlFtp();
typedef struct
{
size_t type; //0:文件夹 1:文件
std::string name; //名称
std::string permissions; //权限
}FILE_INFO, *LPFILE_INFO;
public:
int connect(const char *user, const char *password, const char * ip, short port=21);
void close();
int download(const char * remoteFile, const char * localFile, size_t timeOut=0);
int upload(const char * remoteFile, const char * localFile, size_t timeOut=0);
int dirlist(const char * remote, std::vector &vecFileInfo);
const char * getLastError();
private:
CURL *curl;
std::string m_ip;
std::string m_user;
std::string m_password;
short m_port;
std::string m_lastError;
};
源文件代码如下,
#include "stdafx.h"
#include "HttpsPost.h"
#include
#include
#include
#include
#ifdef WIN32
#include
#else
#include
#endif
//参数文档地址:https://curl.haxx.se/libcurl/c/libcurl-tutorial.html
namespace _CURL_
{
/**
* buf: 从服务器返回的buffer
* unit: buufer的单位
* bufSize: buffer的大小
* data: 保存从服务器返回的内容
* 注意这个函数会被调用多次
*/
static size_t write_data(void *buf, size_t unit, size_t bufSize, std::string * data)
{
int size = unit * bufSize;
char * tmp = (char*)malloc(size + 1);
memcpy(tmp, buf, size);
tmp[size] = '\0';
data->append(tmp);
free(tmp);
return size;
}
static size_t ftp_read(void *ptr, size_t size, size_t nmemb, void *stream)
{
curl_off_t nread;
size_t retcode = fread(ptr, size, nmemb, (FILE *)stream);
nread = (curl_off_t)retcode;
return retcode;
}
//ftp 文件结构
typedef struct FtpFile
{
char filename[512]; //文件名称
FILE *stream; //文件操作指针
}FTP_FILE, *LPFTP_FILE;
static size_t ftp_write(void *buffer, size_t size, size_t nmemb,void *stream)
{
struct FtpFile *out = (struct FtpFile *)stream;
if(out && !out->stream) {
out->stream = fopen(out->filename, "wb");
if(!out->stream)
return -1;
}
return fwrite(buffer, size, nmemb, out->stream);
}
//智能初始化curl库和释放curl库
class CurlIntelligence
{
public:
CurlIntelligence()
{
curl_global_init(CURL_GLOBAL_ALL);
}
~CurlIntelligence()
{
curl_global_cleanup();
}
};
}
_CURL_::CurlIntelligence g_curl;
/*
* 函数:
* replace(替换字符串)
* 参数:
* pszSrc:源字符串
* pszOld:需要替换的字符串
* pszNew:新字符串
* 返回值:
* 返回替换后的字符串
*/
std::string CTools::replace(const char *pszSrc, const char *pszOld, const char *pszNew)
{
std::string strContent, strTemp;
strContent.assign( pszSrc );
std::string::size_type nPos = 0;
while( true )
{
nPos = strContent.find(pszOld, nPos);
if ( nPos == std::string::npos )
{
break;
}
strTemp = strContent.substr(nPos+strlen(pszOld), strContent.length());
strContent.replace(nPos,strContent.length(), pszNew );
strContent.append(strTemp);
nPos +=strlen(pszNew) - strlen(pszOld)+1; //防止重复替换 避免死循环
}
return strContent;
}
const char * CTools::getAppPath()
{
static std::string appPath;
if ( appPath.empty() )
{
char szBuf[1024];
memset(szBuf, '\0', 1024);
#ifdef _WIN32
GetModuleFileName(NULL, szBuf, 1024);
std::string temp = szBuf;
std::string::size_type pos = temp.find_last_of("\\")+1;
appPath = temp.substr(0, pos);
#else
getcwd(szBuf, 1024);
appPath.assign(szBuf);
appPath.append("/");
#endif
}
return appPath.c_str();
}
CUrlHttp::CUrlHttp(void)
{
}
CUrlHttp::~CUrlHttp(void)
{
}
/*
* 函数:
* Request(请求函数)
* 参数:
* strRequestType:请求类型(get,post)
* strUrl:请求url地址
* strReport:回执信息
* strHeader:请求头
* strCookie:cookie信息
* strCaPath:ca转成pem证书路径
* strParam:请求参数(get的时候此参数填空)
* nTimeOut:超时设置默认是0秒 是无限等待
* 返回值:
* 0表示成功 非0表示错误代码
*/
int CUrlHttp::Request(std::string strRequestType,
std::string strUrl,
std::string &strReport,
std::vector vecHeader,
std::string strParam/* ="" */,
std::string strCookie/* ="" */,
std::string strCaPath/* ="" */,
int nTimeOut/* =0 */)
{
CURL * curl;
curl = curl_easy_init();
curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str());
//设置http头
curl_slist * headers = NULL;
for ( int i=0; i 0 )
{
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, nTimeOut);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, nTimeOut);
}
//
if (!strCookie.empty())
{
curl_easy_setopt(curl, CURLOPT_COOKIEFILE, strCookie.c_str());
}
CURLcode code = curl_easy_perform(curl);
if(code != CURLE_OK)
{
printf("curl_wasy_perform error = %s",curl_easy_strerror(code));
}
if ( headers != NULL )
{
curl_slist_free_all(headers);
}
curl_easy_cleanup(curl);
打印出来
//std::string strReportData;
//strReportData.append(strReportHeader);
//strReportData.append(strReport);
//TRACE("request:%s url:%s report:%s", strRequestType.c_str(), strUrl.c_str(), strReportData.c_str());
return code;
}
/*
* 函数:
* RequestSSL(表单提交)
* 参数:
* strUrl:请求url地址
* strReport:回执信息
* vecHeader:请求头
* strCookie:cookie信息
* listParam:表单列表
* strCaPath:ca转成pem证书路径
* nTimeOut:超时设置默认是0秒 是无限等待:
* 返回值:
* 0表示成功 非0表示错误代码
*/
int CUrlHttp::RequestSSL(std::string strUrl,
std::string &strReport,
_POST_LIST_DATA_ listParam,
std::vector vecHeader,
std::string strCookie/* ="" */,
std::string strCaPath/* ="" */,
int nTimeOut/* =0 */)
{
CURLcode code;
CURL * curl;
curl = curl_easy_init();
curl_easy_setopt(curl, CURLOPT_POST, 1);
curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str());
//err = curl_easy_setopt(hCurl, CURLOPT_HTTPHEADER, "dfsdf");
//设置http头
curl_slist * headers = NULL;
for ( int i=0; i 0 )
{
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, nTimeOut);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, nTimeOut);
}
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION,1); //是否抓取跳转后的页面
/* Set the form info */
curl_easy_setopt(curl, CURLOPT_HTTPPOST, post); //
curl_easy_setopt(curl, CURLOPT_HEADER, 0); //不读取返回头的数据
//设置http cookie
if (!strCookie.empty())
{
curl_easy_setopt(curl, CURLOPT_COOKIEFILE, strCookie.c_str());
}
code = curl_easy_perform(curl); /* post away! */
//获取请求返回的值 如:200
//code = curl_easy_getinfo(curl,CURLINFO_RESPONSE_CODE, &RESPONSE_CODE);
/* free the post data again */
if ( headers != NULL )
{
curl_slist_free_all(headers);
}
curl_formfree(post);
curl_easy_cleanup(curl);
return code;
}
/********************************************************************************************
* curl FTP 类封装 *
*
*
*********************************************************************************************/
CUrlFtp::CUrlFtp()
{
curl = NULL;
}
CUrlFtp::~CUrlFtp()
{
close();
}
/*
* 函数:
* connect(ftp连接)
* 参数:
* user:ftp帐号
* password:ftp密码
* ip:ftpip
* port:ftp端口
* 返回值:
* 成功返回0 失败返回-1
*
*/
int CUrlFtp::connect( const char *user, const char *password, const char * ip, short port /*=21*/)
{
curl = curl_easy_init();
if ( curl == NULL )
{
m_lastError.assign("curl initialization failure!");
printf("curl initialization failure!\n");
return -1;
}
//设置登录帐号和密码
std::string spider;
spider.append(user);
spider.append(":");
spider.append(password);
curl_easy_setopt(curl, CURLOPT_USERPWD, spider.c_str());
std::string url;
url.append("ftp://");;
url.append(ip);
if ( port != 0 )
{
url.append(":");
char szPort[10];
sprintf(szPort, "%d", port);
url.append(szPort);
}
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
CURLcode code = curl_easy_perform(curl);
if ( code != CURLE_OK )
{
m_lastError = curl_easy_strerror( code );
printf("ftp connect failure: %s!\n", m_lastError.c_str());
close();
return -1;
}
m_ip.assign(ip);
m_user.assign(user);
m_password.assign(password);
m_port = port;
m_lastError.assign("ftp connect success!");
printf("ftp connect success!\n");
return 0;
}
/*
* 函数:
* close(ftp关闭)
* 参数:
* 无
* 返回值:
* 无
*
*/
void CUrlFtp::close()
{
if ( curl != NULL )
{
curl_easy_cleanup(curl);
curl = NULL;
}
}
/*
* 函数:
* download(ftp文件下载)
* 参数:
* remoteFile:远端文件路径
* localFile:本地文件路径
* timeOut:超时时间 单位秒
* 返回值:
* 成功返回0 失败返回-1
*
*/
int CUrlFtp::download(const char * remoteFile, const char * localFile, size_t timeOut /*= 0*/)
{
if ( curl == NULL )
{
m_lastError.assign("ftp disconnect!");
printf("ftp disconnect!");
return -1;
}
std::string newRemotePath = CTools::replace(remoteFile, "\\", "/" );
std::string newLocalPath = CTools::replace(localFile, "\\", "/" );
_CURL_::FTP_FILE ftpfile;
sprintf(ftpfile.filename, "%s",newLocalPath.c_str());
ftpfile.stream = NULL;
std::string url;
url.append("ftp://");;
url.append(m_ip);
url.append(":");
char szPort[10];
sprintf(szPort, "%d", m_port);
url.append(szPort);
url.append("/");
url.append(newRemotePath);
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, _CURL_::ftp_write);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &ftpfile);
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
if ( timeOut > 0 )
{
curl_easy_setopt(curl, CURLOPT_FTP_RESPONSE_TIMEOUT, timeOut);
}
CURLcode code = curl_easy_perform(curl);
if ( code != CURLE_OK )
{
m_lastError = curl_easy_strerror( code );
printf("ftp download failure: %s!\n", m_lastError.c_str());
return -1;
}
if (ftpfile.stream != NULL )
{
fclose(ftpfile.stream);
ftpfile.stream = NULL;
}
m_lastError.assign("ftp upload success!");
return 0;
}
/*
* 函数:
* upload(ftp文件上传)
* 参数:
* remoteFile:远端文件路径
* localFile:本地文件路径
* timeOut:超时时间 单位秒
* 返回值:
* 成功返回0 失败返回-1
*
*/
int CUrlFtp::upload(const char * remoteFile, const char * localFile, size_t timeOut/*=0*/)
{
if ( curl == NULL )
{
m_lastError.assign("ftp disconnect!");
printf("ftp disconnect!");
return -1;
}
std::string newRemotePath = CTools::replace(remoteFile, "\\", "/" );
std::string newLocalPath = CTools::replace(localFile, "\\", "/" );
CURLcode code;
FILE *hd_src;
struct stat file_info;
curl_off_t fsize;
std::size_t nItem = newRemotePath.find_last_of("/");
std::string remoteFileName = newRemotePath.substr(nItem+1);//文件名称
std::string remotePath = newRemotePath.substr(0, nItem);//远端路径
struct curl_slist *headerlist = NULL;
char buf_1 [256] = "RNFR while-uploading";
char buf_2 [256]; //远端文件名称
sprintf(buf_2,"RNTO %s", remoteFileName.c_str());
if(stat(newLocalPath.c_str(), &file_info))
{
m_lastError.assign("the uploaded file does not exist!");
printf("the uploaded file does not exist(%s)!\n", localFile);
return -1;
}
fsize = (curl_off_t)file_info.st_size;
hd_src = fopen(newLocalPath.c_str(), "rb");
if ( hd_src == NULL )
{
m_lastError.assign("file open failed!");
printf("file open failed(%s)!\n", localFile);
return -1;
}
headerlist = curl_slist_append(headerlist, buf_1);
headerlist = curl_slist_append(headerlist, buf_2);
curl_easy_setopt(curl, CURLOPT_READFUNCTION, _CURL_::ftp_read);
curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
//设置ftp url
std::string url = "ftp://";
url.append(m_ip);
url.append(":");
char szPort[10];
sprintf(szPort, "%d", m_port);
url.append(szPort);
url.append("/");
url.append(remotePath);
url.append("/");
url.append("while-uploading");
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_POSTQUOTE, headerlist);
curl_easy_setopt(curl, CURLOPT_READDATA, hd_src);
curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE,(curl_off_t)fsize);
if ( timeOut > 0 )
{
curl_easy_setopt(curl, CURLOPT_FTP_RESPONSE_TIMEOUT, timeOut);
}
code = curl_easy_perform(curl);
curl_slist_free_all(headerlist);
if ( code != CURLE_OK )
{
fclose(hd_src);
m_lastError = curl_easy_strerror( code );
printf("ftp upload failure: %s!\n", m_lastError.c_str());
return -1;
}
fclose(hd_src);
m_lastError.assign("ftp upload success!");
return code;
}
/*
* 函数:
* dirlist(远端目录列表获取)
* 参数:
* remote:远端目录路径
* vecFileInfo:输出遍历得到的文件夹和文件
* 返回值:
* 成功返回0 失败返回-1
*
*/
int CUrlFtp::dirlist(const char * remote, std::vector &vecFileInfo)
{
if ( curl == NULL )
{
m_lastError.assign("ftp disconnect!");
printf("ftp disconnect!");
return -1;
}
std::string remotePath = CTools::replace(remote, "\\", "/" );
if ( remotePath.size() == 0 )
{
remotePath.append("/");
}
if ( remotePath[remotePath.length()-1] != '/')
{
remotePath.append("/");
}
std::string url;
url.append("ftp://");;
url.append(m_ip);
url.append(":");
char szPort[10];
sprintf(szPort, "%d", m_port);
url.append(szPort);
url.append("/");
url.append(remotePath);
std::string response;
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, _CURL_::write_data);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
CURLcode code = curl_easy_perform(curl);
if ( code != CURLE_OK )
{
m_lastError = curl_easy_strerror( code );
printf("ftp connect failure: %s!\n", m_lastError.c_str());
return -1;
}
//解析ftp数据得到文件和文件夹属性
std::string::size_type pos=0, index=0, len=0;
while( true )
{
std::string row= "";
pos = response.find("\r\n", pos)+2;
if ( pos < index )
{
break;
}
len = pos - index;//需要截取的字符串长度
row = response.substr(index, len); //得到每行数据
index = pos;
std::string::size_type rowPos=0, rowIndex=0, rowLen=0;
//得到名称
FILE_INFO fileInfo;
rowPos = row.find_last_of(' ')+1;
std::string name = row.substr(rowPos, row.length());
if ( name.size() == 0 || name[0] == '.')
{
continue;
}
fileInfo.name = name;
//得到文件权限和文件类型
rowPos = row.find_first_of(' ');
std::string data = row.substr(0,rowPos);
if ( data.size() != 0 )
{
if (data[0] == 'd')
{
//文件夹
fileInfo.type = 0;
fileInfo.permissions = data.substr(1, data.length());
}
else
{
//文件
fileInfo.type = 1;
fileInfo.permissions = data.substr(1, data.length());
}
}
vecFileInfo.push_back(fileInfo);
}
m_lastError.assign("");
return 0;
}
/*
* 函数:
* getLastError(最后错误信息)
* 参数:
* 无
* 返回值:
* 对应的错误信息
*
*/
const char * CUrlFtp::getLastError()
{
return m_lastError.c_str();
}
在C++工程中直接加载这两个文件,curl 库文件如下,解压后放在当前目录。curl库文件获取地址:https://download.csdn.net/download/shufac/11472590
调用libcurl示例如下,
调用libcurl类库时需引用头文件,
#include
using namespace std;
调用方法示例,
void CHttpsPostDemoDlg::OnBnClickedBtnTest()
{
CUrlHttp *curlhttp = new CUrlHttp();
string strReport;
vector vecHeader;
vecHeader.push_back("Content-Type:application/json;charset=UTF-8");
vecHeader.push_back("\"UserAgent\":\"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36\"");
vecHeader.push_back("\"Connection\":\"Keep-Alive\"");
string strParam="{\"method\":\"ToolManger\",\"ack\":1,\"params\":{\"username\":\"shufac\",\"password\":\"shufac\",\"toolid\":\"8\",\"mac\":\"48:4D:7E:AB:BF:EB\"}}";
//std::string strParam="{\"method\":\"ToolManger\",\"ack\":1,\"params\":{\"username\":\"csf\",\"password\":\"csf\",\"toolid\":\"10\",\"mac\":\"48:4D:7E:AB:BF:EB\"}}";
curlhttp->Request("POST","https://oa.notioni.com/notionSystem/a/sw/tools/access/query",strReport,vecHeader,strParam);
CString str = strReport.c_str();
delete curlhttp;
}
返回结果: