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 : 操作每一个文件时, 要成对执行 curl_easy_init 和 curl_easy_cleanup)