curl的简单使用

#include "Base.h"
#include <sys/stat.h>
#include "curl/curl.h"
#include "curl/easy.h"
#include "FileDownload.h"

#define CHECK_CURL_ERROR(ERROR_CODE) if (ERROR_CODE != CURLE_OK){logDebug("%s, code:%d", #ERROR_CODE, int(ERROR_CODE));return;}

static int handleProgressUpdate(void *userData, double totalToDownload, double nowDownloaded, double totalToUpLoad, double nowUpLoaded)
{
    auto self = (FileDownload*)userData;
    if (totalToDownload > 0)
    {
        auto percent = nowDownloaded / totalToDownload * 100;
        if (percent != self->percent)
        {
            self->percent = percent;
            if (self->onDownloadUpdate)
            {
                self->onDownloadUpdate(self, nowDownloaded, totalToDownload);
            }
        }
    }
    return 0;
}
static size_t handleWirte(void *buff, size_t size, size_t nmemb, void *userData)
{
    auto self = (FileDownload*)userData;
    if (self->fileObj == nullptr)
    {
        self->checkOpenFile();
    }
    if (self->fileObj)
    {
        return fwrite(buff, size, nmemb, self->fileObj);
    }
    else
    {
        return 0;
    }
}
static size_t handleHeader(void *ptr, size_t size, size_t nmemb, void *userData)
{
    auto self = (FileDownload*)userData;
    self->checkOpenFile();
    self->errorInfo.append((const char*)ptr, size * nmemb);
    return size * nmemb;
}
static void onDownloadWin32(std::shared_ptr<FileDownload> download)
{
    auto curl = curl_easy_init();
    if (curl == nullptr)
    {
        LOG_DEBUG("%s", "curl_easy_init fail");
        return;
    }
    bool result = false;
    download->fileIndex = 0;
    while (!download->fileNameList.empty())
    {
        download->fileIndex++;
        download->curl = curl;
        auto& fileName = download->fileNameList.front();
        download->curFileName = fileName;
        download->percent = 0;
        auto fileUrl = download->url + fileName;
        auto savePath = download->saveDir + fileName;

        double downloadFileLenth = 0;
        long responseCode = 0;
        CURLcode ret = CURLE_OK;
        bool isExist = cocos2d::FileUtils::getInstance()->isFileExist(savePath);
        if (isExist)
        {
            auto tmpcurl = curl_easy_init();
            CHECK_CURL_ERROR(curl_easy_setopt(tmpcurl, CURLOPT_URL, fileUrl.c_str()));
            CHECK_CURL_ERROR(curl_easy_setopt(tmpcurl, CURLOPT_HTTPGET, 1));    //使用HTTPGET
            CHECK_CURL_ERROR(curl_easy_setopt(tmpcurl, CURLOPT_NOBODY, 1));    //不需求body  
            ret = curl_easy_perform(tmpcurl);
            CHECK_CURL_ERROR(curl_easy_getinfo(tmpcurl, CURLINFO_RESPONSE_CODE, &responseCode));
            if (ret == CURLE_OK && responseCode == 200)
            {
                curl_easy_getinfo(tmpcurl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &downloadFileLenth);
            }
            curl_easy_cleanup(tmpcurl);
        }
        
        struct stat info;
        curl_off_t fileSize = stat(savePath.c_str(), &info) == 0 ? info.st_size : 0;
        if (!isExist || fileSize < (int)downloadFileLenth)
        {
            CHECK_CURL_ERROR(curl_easy_setopt(curl, CURLOPT_URL, fileUrl.c_str()));
            CHECK_CURL_ERROR(curl_easy_setopt(curl, CURLOPT_RESUME_FROM_LARGE, fileSize));
            CHECK_CURL_ERROR(curl_easy_setopt(curl, CURLOPT_WRITEDATA, download.get()));
            CHECK_CURL_ERROR(curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, handleWirte));
            CHECK_CURL_ERROR(curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0));
            CHECK_CURL_ERROR(curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L));
            CHECK_CURL_ERROR(curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, download.get()));
            CHECK_CURL_ERROR(curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, handleHeader));
            CHECK_CURL_ERROR(curl_easy_setopt(curl, CURLOPT_HEADERDATA, download.get()));
            CHECK_CURL_ERROR(curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, handleProgressUpdate));
            CHECK_CURL_ERROR(curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1L));
            CHECK_CURL_ERROR(curl_easy_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, 1L));
            CHECK_CURL_ERROR(curl_easy_setopt(curl, CURLOPT_LOW_SPEED_TIME, 5L));
            CHECK_CURL_ERROR(curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1));
            CHECK_CURL_ERROR(curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0));
            CHECK_CURL_ERROR(curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0));   
            ret = curl_easy_perform(curl);
            CHECK_CURL_ERROR(curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &responseCode));
        }
        
        if (download->fileObj)
        {
            fclose(download->fileObj);
            download->fileObj = nullptr;
        }
        if ((ret == CURLE_OK && responseCode >= 200 && responseCode <= 299) || (ret == CURLE_RANGE_ERROR && responseCode == 416 && fileSize > 0))
        {
            download->fileNameList.erase(download->fileNameList.begin());
            result = true;
        }
        else
        {
            result = false;
            download->errorInfo += curl_easy_strerror(ret);
            if (download->onDownloadError)
            {
                download->onDownloadError(download.get(), download->errorInfo);
            }
            LOG_DEBUG("%s", download->errorInfo.c_str());
            break;
        }
    }
    curl_easy_cleanup(curl);
    if (result)
    {
        if (download->onDownloadFinish)
        {
            download->onDownloadFinish(download.get());
        }
    }
}

void FileDownload::start(std::shared_ptr<FileDownload> download)
{
    if (!download->url.empty())
    {
        if (download->url.back() != '/')
        {
            download->url.push_back('/');
        }
    }
    cocos2d::FileUtils::createDirectory(download->saveDir);
    auto t = std::thread(onDownloadWin32, download);
    t.detach();
}

void FileDownload::checkOpenFile()
{
    curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &responseCode);
    if ((responseCode >= 200 && responseCode <= 299) && fileObj == nullptr)
    {
        fileObj = fopen((saveDir + curFileName).c_str(), "ab+");
    }
}

  

posted @ 2023-03-17 20:37  书山有路,学海无涯  阅读(32)  评论(0编辑  收藏  举报