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+"); } }