近期接到一个项目需求,之前做的软件里边调用的接口所在服务器要改成IPV6,需要我们做好改造支持。
软件使用libcurl开源库实现网络通信的,libcurl本身是支持IPv6的,但可以在编译和使用中关闭或禁用,现在软件直接使用现成的libcurl静态库,之前curl怎么编译的都不知道了,导致现有程序不支持调用IPV6服务的接口。
1. 项目代码中添加支持IPV6测试
查阅资料,curl在使用时,如果要支持IPV6,在代码中调用
CURL_EXTERN CURLcode curl_easy_setopt(CURL curl, CURLoption option, …);
函数添加IPV6功能即可,实际如下:
curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_WHATEVER);
curl为来自于curl_easy_init()初始化创建的CURL的指针,
CURLOPT_IPRESOLVE为设置的类型,表示这次IP解析相关的参数,
CURL_IPRESOLVE_WHATEVER为设置的值,可以设置CURL_IPRESOLVE_V4表示仅支持IPV4,CURL_IPRESOLVE_V6表示仅支持IPV6,和CURL_IPRESOLVE_WHATEVER表示IPV4和IPV6都支持;
修改设置编译后,测试发现还是不支持IPV6。
问题在哪?在于使用的libcurl的静态库可能本身就不支持或被禁用,在libcurl源码(libcurl和后面用到的openssl源码可以自行在开源网站上下载)中查看curl/lib/curl_config.h(有些版本可能是curl_config.h.cmake文件)
查看并设置#define ENABLE_IPV6 1,(,有些是#cmakedefine ENABLE_IPV6 1,1表示源码支持IPV6,0表示不支持)
使用 nmake重新编译curl,curl依赖opensssl开源库,所以为确保编译curl成功,先做好openssl的编译安装工作。
2. 编译openssl库
用nmake编译openssl依次用一下命令,这里用到perl工具:
perl Configure VC-WIN32 no-shared no-asm no-tests -D_WIN32_WINNT=0x0501 --prefix=C:\openssl_lib
nmake
nmake install完成
openssl库编译也比较复杂,可自行查阅资料确保openssl编译安装成功
3. 编译libcurl库
安装完openssl(注意看上面命令中,我们把openssl安装到了C:\openssl_lib下,下面编译curl要用到),开始编译libcurl,使用命令如下:
开始菜单管理员权限打开VS2010命令提示(如果要x86版本,就打开x86命令)
cd /d 到curl目录下的winbuild文件夹中
nmake /f Makefile.vc mode=static VC=10 WITH_DEVEL=C:\openssl_lib WITH_SSL=static MACHINE=x86 ENABLE_SSPI=no ENABLE_IPV6=yes ENABLE_IDN=no debug=no
上面Makefile.vc是启动winbuild文件夹下Makefile.vc文件
mode=static表示本次编译输出libcurl为静态库,若要编译出动态库改为mode=dll即可
VC=10表示编译器用的VS2010版本,你可以用VC=14,表示用的VS2015,其他如VS2008,VS2017,VS2019自行查阅版本号;
WITH_DEVEL=c:\openssl表示当前依赖目录为c:\openssl
WITH_SSL=static表示依赖的openssl库使用静态库
MACHINE=x86表示编译输出32位版本
ENABLE_SSPI=no,ENABLE_IDN=no,debug=no表示禁用SSPI,IDN,debug,若要启用,no改为yes即可;
ENABLE_IPV6=yes就是本次重点,将ENABLE_IPV6设置位yes,表示curl此次编译的支持使用IPV6。
编译完成后,curl目录下生成builds文件夹,在builds文件夹下生成三个子文件夹,取非curl和lib结尾的那个文件夹里边就是我们实际要的,该子文件夹里边"bin"是curl的测试程序,可以直接通过命令行验证,"include"使用curl需要包括的头文件,"lib"编译出来的使用curl需要的静态库。
4. 验证结果
编译出来后,我们直接用"bin"下的curl.exe测试下是否支持IPV6,cmd命令开启,cd /d curl.exe的目录,执行curl IPV6的域名;
很多电脑和网络目前都还不支持IPV6,所以这里测试有问题,可能不是编译的curl有问题,而是你的电脑系统和你使用的网络的原因。
用ping测试电脑支持IPV6与否,cmd里输入命令ping -6 IPV6的IP地址
在浏览器输入网址“http://test-ipv6.com/”,测试你的网络是否支持IPV6
5. 代码引用
在代码中引入curl的头文件,并在配置中加上libcurl的静态库,调用代码大致如下:
int PostEx(const char* strUrl, const char* pszPost,
const char* pszCookie)
{
CURLcode res;
m_strResponse = "";
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);
}
struct curl_slist *headers = NULL;
headers = curl_slist_append(headers, "Postman-Token: b736f1eb-1475-4f8d-ac47-021df32cabe3");
headers = curl_slist_append(headers, "Cache-Control: no-cache");
headers = curl_slist_append(headers, "Content-Type: application/x-www-form-urlencoded");
headers = curl_slist_append(headers, "content-type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_WHATEVER);//这里就是我们添加的设置支持IPV6的代码
curl_easy_setopt(curl, CURLOPT_URL, strUrl);
curl_easy_setopt(curl, CURLOPT_POST, 1);
//strData +=strPost.c_str();
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, pszPost);
curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, OnWriteData);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&m_strResponse);
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 60*5);
if ((pszCookie != NULL)&&(strlen(pszCookie)>0))
{
curl_easy_setopt(curl, CURLOPT_COOKIEFILE, (void *)&pszCookie);
curl_easy_setopt(curl, CURLOPT_COOKIEJAR, (void *)&pszCookie);
}
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 60);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 60);
res = curl_easy_perform(curl);
if (res != CURLE_OK)
m_strResponse = "";
curl_easy_cleanup(curl);
return res;
}