curl : 操作每一个文件时, 要成对执行 curl_easy_init 和 curl_easy_cleanup

/// 操作一个文件的时候,要重新执行 curl_easy_init 和 curl_easy_cleanup
/// 否则第二个文件之后的的取文件长度和下载会失败

HRESULT CTask::Download(std::string & strFirstFile, std::string & strSecondFile)
{
    USES_CONVERSION;

    CDlProcess  dlProcess;
    CURLcode    recode;
    CURL *      pCurl = NULL;

    int         iSleepCnt = 0;
    int         iTaskCnt = 0;
    double      fFileSize = 0;

    /// 整个进程中, 只执行一次
    /// @todo 这个在函数外面做
    if (!g_bCurlInit)
    {
        curl_global_init(CURL_GLOBAL_WIN32);
        g_bCurlInit = TRUE;
    }

    /// 每下载一个文件, 需要执行一对 curl_easy_init(),curl_easy_cleanup 
    if (!strFirstFile.empty())
    {
        pCurl = curl_easy_init();
        if (NULL == pCurl)
            return S_FALSE;

        fFileSize = ReturnFileLength(pCurl, strFirstFile);
        dlProcess.SetFileSize(fFileLength); ///< 向所有者汇报下载进度时用的

        /// 下载前,将本地已经存在的要保存的本地文件删除
        /// @todo g_strFirstFile_Local 是随函数入参传进来的
        ns_base::DeleteFilePro(A2W(g_strFirstFile_Local.c_str()));

        if ((fFileLength > 0)
            && (dlProcess.OpenFileToWrite(g_strFirstFile_Local.c_str())))
        {
            curl_easy_setopt(pCurl, CURLOPT_URL, strFirstFile.c_str());  
            curl_easy_setopt(pCurl, CURLOPT_NOSIGNAL, 1L);

            /// C++方式的回调
            dlProcess.SetParentHWND(g_hParentHandle);
            dlProcess.SetCUrl(pCurl);
            curl_easy_setopt(pCurl, CURLOPT_WRITEDATA, &dlProcess);
            curl_easy_setopt(pCurl, CURLOPT_WRITEFUNCTION, &CDlProcess::CallBackProc_WriteFileFromDownLoad);

            recode = curl_easy_perform(pCurl);
            curl_easy_setopt(pCurl, CURLOPT_NOSIGNAL, 0L); ///< 复原参数
            dlProcess.CloseFile();
        }

        curl_easy_cleanup(pCurl); ///< !

        ///< @todo 返回的是 recode 相关的结果
        ::PostMessageW(g_hParentHandle, WM_DL_FIRST_FILE_OK, 0, 0);
    }

    pCurl = curl_easy_init();   ///< 换了一个远程文件, 需要重新执行初始化
    if (NULL == pCurl)
        return S_FALSE;

    /// 正式下载前, 得到远程文件size
    /// @todo 可以将操作每一个远程文件的操作封装成一个函数
    fFileLength = ReturnFileLength(pCurl, strSecondFile);
    dlProcess.SetFileSize(fFileLength);

    /// 下载前,将本地已经存在的要保存的本地文件删除
    ns_base::DeleteFilePro(A2W(g_strSecondFile_Local.c_str()));

    if ((fFileLength > 0) 
        && dlProcess.OpenFileToWrite(g_strSecondFile_Local.c_str()))
    {
        curl_easy_setopt(pCurl, CURLOPT_URL, strSecondFile.c_str());  
        curl_easy_setopt(pCurl, CURLOPT_NOSIGNAL, 1L);

        /// C++方式的回调
        dlProcess.SetParentHWND(g_hParentHandle); ///< g_hParentHandle 随参数传进来的
        dlProcess.SetCUrl(pCurl);
        curl_easy_setopt(pCurl, CURLOPT_WRITEDATA, &dlProcess);
        curl_easy_setopt(pCurl, CURLOPT_WRITEFUNCTION, &CDlProcess::CallBackProc_WriteFileFromDownLoad);

        recode = curl_easy_perform(pCurl);
        curl_easy_setopt(pCurl, CURLOPT_NOSIGNAL, 0L); ///< 复原参数
        curl_easy_cleanup(pCurl);
        dlProcess.CloseFile();

        ///< @todo 返回的是 recode 相关的结果
        ::PostMessageW(g_hParentHandle, WM_DL_SECOND_FILE_OK, 0, 0);
    }

    return S_OK; ///< @todo 返回的是 recode 相关的结果
}

// return file size
double CTask::ReturnFileLength(CURL* pCurl, string strURL)
{
    if (strURL.empty())
        return 0;

    double fFileLength = 0.0;
    if (NULL != pCurl)
    {
        curl_easy_setopt(pCurl, CURLOPT_URL, strURL.c_str());
        curl_easy_setopt(pCurl, CURLOPT_HEADER, 1L);    //只需要header头
        curl_easy_setopt(pCurl, CURLOPT_NOBODY, 1L);    //不需要body
        curl_easy_perform(pCurl);
        curl_easy_getinfo(pCurl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &fFileLength);

        ///取得信息后, 将改过的参数复原
        curl_easy_setopt(pCurl, CURLOPT_HEADER, 0L);
        curl_easy_setopt(pCurl, CURLOPT_NOBODY, 0L);
    }

    if (fFileLength ==  -1)
        fFileLength = 0.0f;

    return fFileLength;
}


`curl_global_init`和`curl_easy_init`都是libcurl库中的初始化函数,但是它们的作用不同。 `curl_global_init`用于初始化libcurl库的全局环境,包括SSL、Winsock等。它只需要在程序运行调用一次。如果在多线程中使用libcurl库,应该在每个线程中调用`curl_global_init`函数来初始化全局环境。如果没有调用`curl_global_init`,则在使用libcurl会自动调用它进行初始化。 `curl_easy_init`用于初始化一个CURL句柄,CURL句柄用于执行HTTP请求和处理响应。每个HTTP请求需要创建一个CURL句柄,当HTTP请求完成后,需要使用`curl_easy_cleanup`函数清理CURL句柄。 在使用libcurl,应该先调用`curl_global_init`函数初始化全局环境,然后在需要执行HTTP请求,使用`curl_easy_init`函数初始化一个CURL句柄。在HTTP请求完成后,使用`curl_easy_cleanup`函数清理CURL句柄,并在程序结束调用`curl_global_cleanup`函数释放所有全局资源。 以下是一个示例,用于初始化libcurl库的全局环境并执行HTTP请求: ```c #include <stdio.h> #include <curl/curl.h> int main(void) { CURL *curl; CURLcode res; curl_global_init(CURL_GLOBAL_DEFAULT); // 初始化全局环境 curl = curl_easy_init(); // 初始化CURL句柄 if (curl) { curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); res = curl_easy_perform(curl); // 执行HTTP请求 if (res != CURLE_OK) { fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); } curl_easy_cleanup(curl); // 清理CURL句柄 } curl_global_cleanup(); // 释放全局资源 return 0; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值