Libcurl的编译_HTTP/HTTPSclient源代码演示样例

时间:2021-12-10 16:46:22

HTTP/HTTPSclient源代码演示样例

环境:  zlib-1.2.8  openssl-1.0.1g  curl-7.36

Author:  Kagula

LastUpdateDate: 2016-05-09

阅读前提:CMake工具的基本使用、配置openssl-1.0.1g 开发环境

编译zlib库

下载zlib-1.2.8.tar.gz并解压缩到" D:\SDK\zlib-1.2.8",使用CMake工具生成zlib.sln。在Visual Studio2013中打开并编译就可以。

编译curl-7.36.0

如果Open SSL已经安装到“D:\SDK\openssl-1.0.1g”,先设置以下的环境变量

OPENSSL_LIBRARIES=D:\SDK\openssl-1.0.1g\out32

OPENSSL_ROOT_DIR=D:\SDK\openssl-1.0.1g

从http://curl.haxx.se/下载curl-7.36.0.zip并解压缩到“D:\SDK\curl-7.36.0”启动CMake工具Configure,分别设置LIB_EAY_RELEASE和SSL_EAY_RELEASE变量为“D:\SDK\openssl-1.0.1g\out32\libeay32.lib”,“D:\SDK\openssl-1.0.1g\out32\ssleay32.lib”,产生sln文件后打开,为里面的curlproject项目加入“USE_MANUAL”宏定义,然后build里面的4个项目成功。

为项目加入链接库libcurl_imp.lib  , 把libcurl.dll文件拷贝到C++项目路径下,否则程序执行会提示找不到动态链接库。

以下是HTTP/HTTPSclient演示样例

怎样使用

#include <iostream>
#include <string> using namespace std; #include "httpclient.h" int main(int argc, char *argv[])
{
string response; //login
kagula::network::CHttpClient client;
int nR = client.Post("https://lijun:8443/escortcashbox/main/login.do",
"data={\"version\":\"1.0.0.0\",\"user\":\"admin\",\"password\":\"123\"}",
response,true,
"d:\cookie.txt",
"D:/workspace_qt/build-escortcashbox_c-Mingw32-Debug/debug/tomcat7.pem",
"D:/workspace_qt/build-escortcashbox_c-Mingw32-Debug/debug/client_all.pem",
"123456");
cout << nR << endl <<response << endl; //upload png file
/*
std::map<std::string,std::string> mapFields;
std::map<std::string,std::vector<std::string>> mapFiles;
mapFields["data"] = "{\"version\":\"1.0.0.0\",\"socialid\":\"1012\",\"realname\":\"realnamevalue\",\"portrait\":\"protraitvalue\",\"fingerid\":\"fingeridvalue\",\"groupid\":\"123\"}";
std::vector<std::string> vecFile(2);
vecFile[0] = "d:\\b.png";
vecFile[1] = "image/png";
mapFiles["portraitFile"] = vecFile;
nR = client.MultipartFormdata("https://lijun:8443/escortcashbox/main/escortStaffAdd.do",
mapFields,mapFiles,
response,
"d:\cookie.txt",
"D:/workspace_qt/build-escortcashbox_c-Mingw32-Debug/debug/tomcat7.pem",
"D:/workspace_qt/build-escortcashbox_c-Mingw32-Debug/debug/client_all.pem",
"123456"); cout << nR << endl << response << endl;
*/
//download png file
nR = client.GetFile("https://lijun:8443/escortcashbox/upload/img/20160527_110514_679_426.png",
"d:/ee.png",
"d:\cookie.txt",
"D:/workspace_qt/build-escortcashbox_c-Mingw32-Debug/debug/tomcat7.pem",
"D:/workspace_qt/build-escortcashbox_c-Mingw32-Debug/debug/client_all.pem",
"123456");
cout << nR << endl; return 0;
}

HttpClient.h封装好的头文件

//HttpClient.h源码清单
#ifndef _HTTPCLIENT_H_
#define _HTTPCLIENT_H_ #include <string>
#include <map>
#include <vector> /*
Title: Get Response from Web Server by HTTP/HTTPS method.
Environment:
Windows 7SP1, Windows 8.1, Windows 10
QT Creator 3.5.1, Visual Studio 2013 Update1, Visual Studio 2013 Update5
libcurl 7.36.0, libcurl 7.46.0, Qt 5.6, MSYS2 64bits gcc 5.3.0
Last Update: 2016-05-27
Remark:
[1]假设要在多线程方式下同一时候调用多个CHttpClient实例。
须要在App初始化的时候调用kagula::network::Init();
在App结束的时候调用kagula::network::Cleanup();
[2]编译libcurl必须打开zlib标志。而且把OpenSSL也链进去。 Reference:
curl_eay_setopt manual
http://www.helplib.net/s/linux.die/65_2740/man-3-curl-easy-setopt.shtml
C++ cout format
http://www.cnblogs.com/devymex/archive/2010/09/06/1818754.html
*/ namespace kagula
{
namespace network
{
void Init();
void Cleanup(); class CHttpClient
{
public:
CHttpClient(void);
~CHttpClient(void); public:
/**
* @brief HTTP/HTTPS POST/GET请求
* @param strUrl 输入參数,请求的Url地址,如:https://www.alipay.com
* @param strPost 输入參数,使用例如以下格式para1=val1¶2=val2&…
* @param strCookie 输入參数,Cookie文件名称,比如 d:\temp\cookie.txt
* 假设为空,不启用Cookie.
* @param strResponse 输出參数,返回的内容
* @param bPost 是否Post方式发送请求,默认Post方式发送请求。
* @param pCaPath 输入參数,为CA证书的路径.假设输入为NULL,则不验证server端证书的有效性.
* @param pClientCalPath 输入參数,为client证书的路径.假设输入为NULL,则不验证client证书的有效性.
* @param pClientCalPassword 输入參数,为client证书的存取password.
* @return 返回是否Post成功
* 0 成功
* 7 无法连接
* 28 超时
* 58 服务端验证client证书失败。
* 60 client验证服务端证书失败。
*/
int Post(const char* pUrl,
const char* pPost,
std::string &strResponse,
bool bPost,
const char* pCookie,
const char* pCaPath = NULL,
const char* pClientCalPath = NULL,
const char* pClientCalPassword = NULL); int MultipartFormdata(const char *pUrl,
const std::map<std::string,std::string> & mapFields,
const std::map<std::string,std::vector<std::string>> & mapFiles,
std::string & strResponse,
const char *pCookie,
const char * pCaPath = NULL,
const char * pClientCalPath = NULL,
const char * pClientCalPassword = NULL); int GetFile(const char* pUrl,
const char* pLocalFullPath,
const char* pCookie,
const char* pCaPath = NULL,
const char* pClientCalPath = NULL,
const char* pClientCalPassword = NULL);
public:
void SetDebug(bool bDebug);
std::string getMsgInChinese(int code); private:
bool m_bDebug; bool PrintCookies(void* curl, std::string& strOut);
};
}
}
#endif

源文件清单

//HttpClient.cpp源码清单
#include "HttpClient.h"
#include <iostream>
#include <curl/curl.h>
#include <iomanip>
#include <sstream> #ifdef WIN32
#pragma comment(lib,"libcurl_imp.lib")
#endif namespace kagula
{
namespace network
{
CHttpClient::CHttpClient(void) :
m_bDebug(false)
{ } CHttpClient::~CHttpClient(void)
{ } bool CHttpClient::PrintCookies(void* curl, std::string& strOut)
{
std::ostringstream ostr; CURLcode res;
struct curl_slist *cookies; res = curl_easy_getinfo(curl, CURLINFO_COOKIELIST, &cookies);
if (res != CURLE_OK) { ostr << "Curl curl_easy_getinfo failed:" << curl_easy_strerror(res) << std::endl;
strOut = ostr.str();
return false;
}
const struct curl_slist *nc = cookies;
int i = 1;
ostr << "Cookies, curl knows:" << std::endl;
while (nc) {
ostr << "[" << i++ << "]: " << nc->data << std::endl;
nc = nc->next;
} return true;
} 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;
} size_t OnWriteData_Post(void* buffer, size_t size, size_t nmemb, void* lpVoid)
{
std::string* str = reinterpret_cast<std::string*>(lpVoid);
if (NULL == str || NULL == buffer)
{
return -1;
} char* pData = reinterpret_cast<char*>(buffer);
str->append(pData, size * nmemb);
return nmemb;
} size_t OnWriteData_MultipartFormdata( void *inBuffer, size_t size, size_t nmemb, void *outBuffer )
{
int len = size * nmemb;
char *temp = new char[len+1];
memcpy(temp,inBuffer,len);
temp[len]=0;
reinterpret_cast<std::string *>(outBuffer)->append(temp);
delete temp;
return len;
} size_t OnWriteData_GetFile(void *inBuffer, int size, int nmemb, std::string &content)
{
long len = size * nmemb;
std::string temp((char *)inBuffer, len);
content += temp;
return len;
} std::string CHttpClient::getMsgInChinese(int code)
{
switch(code)
{
case 0:
return "通讯成功";
case 7:
return "server连接失败。";
case 28:
return "连接超时。";
case 58:
return "服务端验证client证书失败。";
case 60:
return "client验证服务端证书失败。 ";
default:
return "";
}
} int CHttpClient::Post(const char* pUrl,
const char* pPost,
std::string & strResponse,
bool bPost,
const char* pCookie,
const char* pCaPath,
const char* pClientCalPath,
const char* pClientCalPassword)
{
strResponse = ""; CURLcode res;
CURL* curl = curl_easy_init();
if (NULL == curl)
{
return CURLE_FAILED_INIT;
}
if (m_bDebug)
{
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, OnDebug);
}
curl_easy_setopt(curl, CURLOPT_URL, pUrl);
if(bPost)
{
curl_easy_setopt(curl, CURLOPT_POST, 1);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, pPost);
}
curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, OnWriteData_Post);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&strResponse);
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); if (pCookie!=0)
{
curl_easy_setopt(curl, CURLOPT_COOKIEFILE, (void *)pCookie);
curl_easy_setopt(curl, CURLOPT_COOKIEJAR, (void *)pCookie);
} if (NULL == pCaPath)
{
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false); //须要在编译curl的时候,一同编译zlib标志。要不然找不到这个标志.
//当然前提是你已经编译完毕zlib.
//发出接受gzip压缩内容的请求,假设server支持gzip内容,会返回压缩后的数据。
//假设Httpserver不支持gzip encoding也不影响libcurl正常工作。 //接受数据的时候,假设返回的是压缩数据,libcurl会自己主动解压数据。 curl_easy_setopt(curl, CURLOPT_ACCEPT_ENCODING, "gzip");
}
else
{
//缺省情况就是PEM,所以无需设置。另外支持DER
//curl_easy_setopt(curl,CURLOPT_SSLCERTTYPE,"PEM");
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, true);
curl_easy_setopt(curl, CURLOPT_CAINFO, pCaPath); //服务端须要认证client的真实性,即双向认证。
if(pClientCalPath!=NULL)
{
curl_easy_setopt(curl,CURLOPT_SSLCERT, pClientCalPath);
curl_easy_setopt(curl,CURLOPT_SSLCERTPASSWD, pClientCalPassword);
curl_easy_setopt(curl,CURLOPT_SSLCERTTYPE, "PEM");
curl_easy_setopt(curl,CURLOPT_SSLKEY, pClientCalPath);
curl_easy_setopt(curl,CURLOPT_SSLKEYPASSWD, pClientCalPassword);
curl_easy_setopt(curl,CURLOPT_SSLKEYTYPE, "PEM");
}
}
//
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 3);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 3); //Webserver通常会重定向链接。比方訪问http:/xxx/x1.do自己主动转到http:/xxx/x2.do
//所以一定要设置CURLOPT_FOLLOWLOCATION为1,否则重定向后的数据不会返回。 curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION,1); res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
return res;
} int CHttpClient::MultipartFormdata(const char *pUrl,
const std::map<std::string,std::string> & mapFields,
const std::map<std::string,std::vector<std::string>> & mapFiles,
std::string & strResponse,
const char *pCookie,const char * pCaPath,
const char * pClientCalPath,const char * pClientCalPassword)
{
CURL *curl;
CURLcode res; curl = curl_easy_init();
strResponse =""; curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, OnWriteData_MultipartFormdata);//write_data
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &strResponse); struct curl_httppost *formpost = 0;
struct curl_httppost *lastptr = 0; //
std::map<std::string,std::string>::const_iterator iterFields = mapFields.begin();
while(iterFields!=mapFields.end())
{
//curl_formadd(&formpost, &lastptr,CURLFORM_COPYNAME,"data",CURLFORM_COPYCONTENTS, pData,CURLFORM_END);
curl_formadd(&formpost, &lastptr,CURLFORM_COPYNAME,iterFields->first.c_str(),
CURLFORM_COPYCONTENTS, iterFields->second.c_str(),CURLFORM_END);
iterFields++;
} std::map<std::string,std::vector<std::string>>::const_iterator iterFiles = mapFiles.begin();
while(iterFiles!=mapFiles.end())
{
//"image/jpeg","image/png"
//curl_formadd(&formpost, &lastptr,CURLFORM_PTRNAME, "portraitFile", CURLFORM_FILE, pImageFileName,CURLFORM_CONTENTTYPE, "image/png", CURLFORM_END);
curl_formadd(&formpost, &lastptr,CURLFORM_PTRNAME,
iterFiles->first.c_str(), CURLFORM_FILE,
iterFiles->second[0].c_str(),CURLFORM_CONTENTTYPE,
iterFiles->second[1].c_str(), CURLFORM_END);
iterFiles++;
} //
curl_easy_setopt(curl, CURLOPT_URL, pUrl);
curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost); if (pCookie!=0)
{
curl_easy_setopt(curl, CURLOPT_COOKIEFILE, (void *)pCookie);
curl_easy_setopt(curl, CURLOPT_COOKIEJAR, (void *)pCookie);
} //单向认证用
if(pCaPath!=0)
{
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, true);
curl_easy_setopt(curl, CURLOPT_CAINFO, pCaPath);
} //服务端须要认证client的真实性。即双向认证。
if(pClientCalPath!=0 && pClientCalPassword!=0)
{
curl_easy_setopt(curl,CURLOPT_SSLCERT, pClientCalPath);
curl_easy_setopt(curl,CURLOPT_SSLCERTPASSWD, pClientCalPassword);
curl_easy_setopt(curl,CURLOPT_SSLCERTTYPE, "PEM");
curl_easy_setopt(curl,CURLOPT_SSLKEY, pClientCalPath);
curl_easy_setopt(curl,CURLOPT_SSLKEYPASSWD, pClientCalPassword);
curl_easy_setopt(curl,CURLOPT_SSLKEYTYPE, "PEM");
} res = curl_easy_perform(curl);
curl_easy_cleanup(curl); curl_formfree(formpost);
return res;
} int CHttpClient::GetFile(const char* pUrl,
const char* pLocalFullPath,
const char* pCookie,
const char* pCaPath,
const char* pClientCalPath,
const char* pClientCalPassword)
{
CURL *curl = NULL;
CURLcode code;
char bufError[CURL_ERROR_SIZE];
std::string content;
long retcode = 0; code = curl_global_init(CURL_GLOBAL_DEFAULT);
if (code != CURLE_OK)
{
//printf("Failed to global init default [%d]\n", code);
return -100;
} curl = curl_easy_init();
if (curl == NULL)
{
//printf("Failed to create CURL connection\n");
return -200;
}
code = curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, bufError);
if (code != CURLE_OK)
{
//printf("Failed to set error buffer [%d]\n", code);
return code;
}
//curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
code = curl_easy_setopt(curl, CURLOPT_URL, pUrl);
if (code != CURLE_OK)
{
//printf("Failed to set URL [%s]\n", error);
goto _END;
}
code = curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
if (code != CURLE_OK)
{
//printf("Failed to set redirect option [%s]\n", error);
goto _END;
}
code = curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, OnWriteData_GetFile);
if (code != CURLE_OK)
{
//printf("Failed to set writer [%s]\n", error);
goto _END;
}
code = curl_easy_setopt(curl, CURLOPT_WRITEDATA, &content);
if (code != CURLE_OK)
{
//printf("Failed to set write data [%s]\n", error);
goto _END;
} if (pCookie!=0)
{
curl_easy_setopt(curl, CURLOPT_COOKIEFILE, (void *)pCookie);
curl_easy_setopt(curl, CURLOPT_COOKIEJAR, (void *)pCookie);
} //单向认证用
if(pCaPath!=0)
{
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, true);
curl_easy_setopt(curl, CURLOPT_CAINFO, pCaPath);
} //服务端须要认证client的真实性。即双向认证。
if(pClientCalPath!=0 && pClientCalPassword!=0)
{
curl_easy_setopt(curl,CURLOPT_SSLCERT, pClientCalPath);
curl_easy_setopt(curl,CURLOPT_SSLCERTPASSWD, pClientCalPassword);
curl_easy_setopt(curl,CURLOPT_SSLCERTTYPE, "PEM");
curl_easy_setopt(curl,CURLOPT_SSLKEY, pClientCalPath);
curl_easy_setopt(curl,CURLOPT_SSLKEYPASSWD, pClientCalPassword);
curl_easy_setopt(curl,CURLOPT_SSLKEYTYPE, "PEM");
} code = curl_easy_perform(curl);
if (code != CURLE_OK)
{
//printf("Failed to get '%s' [%s]\n", URL, error);
goto _END;
} code = curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &retcode);
if ((code == CURLE_OK) && retcode == 200)
{
double length = 0;
code = curl_easy_getinfo(curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &length);
//printf("%d", retcode);
FILE * file = fopen(pLocalFullPath, "wb");
fseek(file, 0, SEEK_SET);
fwrite(content.c_str(), 1, (size_t)length, file);
fclose(file); code = CURLE_OK;
goto _END;
}
_END:
curl_easy_cleanup(curl); return code;
} ///////////////////////////////////////////////////////////////////////////////////////////////
void CHttpClient::SetDebug(bool bDebug)
{
m_bDebug = bDebug;
} void Init()
{
//the function is not thread safe.
curl_global_init(CURL_GLOBAL_ALL);
} void Cleanup()
{
curl_global_cleanup();
}
}
}

注意:

[1]MSys64 Mingw32 QtCreator 32位C++程序 配置libcurl

如果Msys64是安装在C盘默认路径上

第一步:在Msys64中查询可用的curl包

pacman -Ss curl

第二步:安装

pacman -S mingw-w64-i686-curl

第三步:在.pro文件下增加以下的代码

LIBS += C:\msys64\mingw32\lib\libcurl.dll.a

INCLUDEPATH += C:\msys64\mingw32\include

最后:编译链接依赖libcurl的项目成功。

[2]怎样产生cer文件

https原理及tomcat配置https方法

http://jingyan.baidu.com/article/a948d6515d3e850a2dcd2ee6.html

[3]单向认证。让client信任服务端证书

第一步:

双击从服务端keystore中导出的cer文件能够导入证书。

windows下“certmgr.msc”命令能够进入证书管理。

自己制作的证书导入到Win7后默认在“中级证书颁发机构”->“证书”节点里。





第二步:

须要把你做的证书拖到“受信任的根证书颁发机构”->“证书”节点中去,否则

浏览器会提醒“此站点出具的安全证书不是由受信任的证书颁发机构颁发的”等类似错误。

chrome须要重新启动。IE直接刷新页面。就不会出现警告了。

注意:

数字证书转换cer---pem 

在Msys2 Shell中确保安装好openssl.

在Msys2 Shell中使用openssl命令后进入openssl提示符。输入以下的命令

x509 -inform der -in d:/MyServerSecurity/tomcat7.cer -out d:/MyServerSecurity/tomcat7.pem

[4]双向认证。让服务端信任client的证书

相当于“Https单向认证”,加入了“服务端验证client身份真实性”的动作。

须要注意的是:服务端的密钥库參数“CN”必须与服务端的IP地址同样,否则会报错,client的随意。

假设服务端的CN为lijun,则client不能为lijun。即这两个不能是同一个名字。





第一步:client生成证书(用于服务端验证client)

keytool -validity 365 -genkeypair -v -alias kagula -keyalg RSA -storetype PKCS12 -keystore D:\MyClientSecurity\kagulakey.p12 -storepass 123456 -keypass 123456

kagula为证书的名称,D:\MyClientSecurity\kagulakey.p12证书的存放位置。





第二步:证书格式转为cer文件。

keytool -export -v -alias kagula -keystore D:\MyClientSecurity\kagulakey.p12 -storetype PKCS12 -storepass 123456 -rfc -file D:\MyClientSecurity\kagulakey.cer

kagula为证书的名称。D:\MyClientSecurity\kagulakey.p12证书的存放位置。123456证书password,D:\MyClientSecurity\kagulakey.cer导出的文件。





第三步:加入到(或新建)一个keystore文件

keytool -import -v -alias kagula -file D:\MyClientSecurity\kagulakey.cer -keystore D:\MyServerSecurity\tomcat7_client.keystore -storepass 123456

tomcat7_client.keystore假设不存在就会新建一个keystore,假设存在会加入到已经存在的keystore中。

第四步:查看keystore文件里的内容

keytool -list -keystore D:\MyServerSecurity\tomcat7_client.keystore





第五步:改动tomcat7中的server.xml文件

原单向认证的配置例如以下

    <Connector port="8443" protocol="org.apache.coyote.http11.Http11Protocol"

               maxThreads="150" SSLEnabled="true" scheme="https" secure="true"

               clientAuth="false" sslProtocol="TLS" 

               keystoreFile="D:\\MyServerSecurity\\tomcat7.keystore" keystorePass="123456"/>

               

               

如今改动后。例如以下

    <Connector port="8443" protocol="org.apache.coyote.http11.Http11Protocol"

               maxThreads="150" SSLEnabled="true" scheme="https" secure="true"

               clientAuth="true" sslProtocol="TLS"

               keystoreFile="D:\\MyServerSecurity\\tomcat7.keystore" keystorePass="123456"

  truststoreFile="D:\\MyServerSecurity\\tomcat7_client.keystore" truststorePass="123456"/>           

加入了最后一行属性使它指向客户端证书,并把clientAuth属性从false改为true。





第六步(可选):

Step6-1:

測试Windows下的Chrome是否还能訪问server,果然刷新浏览器后

“https://lijun:8443/escortcashbox/main/aboutUs.do”返回错误信息

Step6-2:

測试libcurl是否还能訪问server。如今libcurl返回7(无法连接server)的错误信息。





最后一步-让Windows下的Chrome和IE能訪问服务端:

双击D:\MyClientSecurity\kagulakey.p12文件,“不须要加入到受信任的根证书机构”结点。直接导入证书就可以。

默认在certmgr.msc命令,“个人”->“证书”节点下。





最后一步-让libcurl能訪问服务端:

使用msys64打开openssl命令行工具

#client个人证书的公钥

openssl>pkcs12 -in D:\MyClientSecurity\myclientkey.p12 -out D:\MyClientSecurity\client_publickey.pem -nokeys

或许假设在当前command shell下能找到openssl.exe也能够用以下的命令

“openssl pkcs12 -in D:\MyClientSecurity\myclientkey.p12 -out D:\MyClientSecurity\client_publickey.pem -nokeys”





#client个人证书的私钥

openssl pkcs12 -in D:\MyClientSecurity\myclientkey.p12 -out D:\MyClientSecurity\client_privatekey.pem -nocerts -nodes





#也能够转换为公钥与私钥合二为一的文件;     client公钥与私钥,一起存在all.pem中

openssl>pkcs12 -in D:\MyClientSecurity\kagulakey.p12 -out D:\MyClientSecurity\client_all.pem -nodes









1、使用client_publickey.pem + client_privatekey.pem  (未在win console shell下測试)

curl -k --cert client_publickey.pem --key D:\MyClientSecurity\client_privatekey.pem https://lijun:8443/escortcashbox/main/aboutUs.do





2、能够在Msys64 Shell中运行curl命令(假设已经安装了curl)...使用all.pem

curl -k --cert /d/MyClientSecurity/client_all.pem https://lijun:8443/escortcashbox/main/aboutUs.do





以下是双向认证的參考资料

SSL——Secure Sockets Layer

http://www.blogjava.net/icewee/archive/2012/06/04/379947.html

补充阅读资料

使用libcurl实现上传文件到FTPserver

http://blog.csdn.net/lee353086/article/details/5823145

使用libcurl下载http://www.baidu.com/img/baidu.gif演示样例

http://www.cppblog.com/qiujian5628/archive/2008/06/28/54873.html

libcurl的使用总结(一)

http://www.vimer.cn/2010/03/libcurl%E7%9A%84%E4%BD%BF%E7%94%A8%E6%80%BB%E7%BB%93%EF%BC%88%E4%B8%80%EF%BC%89.html

PHP的curl实现get。post 和 cookie

http://www.tsingpost.com/articles/201403/525.html