QT使用LibCurl多线程下载单个文件的封装类
参考了代码QT中使用libCurl实现多线程分块下载单个文件,封装成QT使用的类,对于进度显示更方便,默认最多使用4个线程下载单个文件。//author:autumoon//联系QQ:4589968//日期:2020-11-23#ifndef QLIBCURL_H#define QLIBCURL_H#include <QObject>//回调函数序列typedef int (*pPro
·
参考了代码QT中使用libCurl实现多线程分块下载单个文件,封装成QT使用的类,对于进度显示更方便,默认最多使用4个线程下载单个文件。

//author:autumoon
//联系QQ:4589968
//日期:2020-11-23
#ifndef QLIBCURL_H
#define QLIBCURL_H
#include <QObject>
//回调函数序列
typedef int (*pProgressFunc)(void *ptr, double totalToDownload, double nowDownloaded, double totalToUpLoad, double nowUpLoaded);
class QLibCurl : public QObject
{
Q_OBJECT
public:
explicit QLibCurl(QObject *parent = nullptr);
//使用多个线程下载单个文件
bool DownLoad(int threadNum, std::string Url, std::string Path, std::string fileName);
public slots:
Q_SIGNALS:
//第三个参数为线程id,取值0到3,分别代表四个下载线程的进度
void progress(qint64, qint64, int);
void finished(bool);
private:
long getDownloadFileLenth (const char *url);
static size_t writeFunc (void *ptr, size_t size, size_t nmemb, void *userdata);
static void *workThread (void *pData);
void sleep(int msec);
private:
//最多使用4个线程下载单个文件,同时显示各自的进度
static int nProgress0(void *ptr, double totalToDownload, double nowDownloaded, double totalToUpLoad, double nowUpLoaded);
static int nProgress1(void *ptr, double totalToDownload, double nowDownloaded, double totalToUpLoad, double nowUpLoaded);
static int nProgress2(void *ptr, double totalToDownload, double nowDownloaded, double totalToUpLoad, double nowUpLoaded);
static int nProgress3(void *ptr, double totalToDownload, double nowDownloaded, double totalToUpLoad, double nowUpLoaded);
private:
static bool m_busy;
static int threadCnt;
static pthread_mutex_t g_mutex;
static std::vector<pProgressFunc> m_vpProgressFunc;
static QLibCurl* m_pLibCurl;
};
#endif // QLIBCURL_H
实现文件:
//author:autumoon
//联系QQ:4589968
//日期:2020-11-23
#include "QLibCurl.h"
#include "curl/curl.h"
#include <QEventLoop>
#include <QTimer>
//全局变量,共用
bool QLibCurl::m_busy = false;
int QLibCurl::threadCnt = 0;
QLibCurl* QLibCurl::m_pLibCurl = nullptr;
pthread_mutex_t QLibCurl::g_mutex = PTHREAD_MUTEX_INITIALIZER;
std::vector<pProgressFunc> QLibCurl::m_vpProgressFunc;
struct tNode
{
FILE *fp;
long startPos;
long endPos;
void *curl;
pthread_t tid;
};
QLibCurl::QLibCurl(QObject *parent) : QObject(parent)
{
m_vpProgressFunc.push_back(&QLibCurl::nProgress0);
m_vpProgressFunc.push_back(&QLibCurl::nProgress1);
m_vpProgressFunc.push_back(&QLibCurl::nProgress2);
m_vpProgressFunc.push_back(&QLibCurl::nProgress3);
m_pLibCurl = this;
}
bool QLibCurl::DownLoad(int threadNum, std::string Url, std::string Path, std::string fileName)
{
if(m_busy)
{
return false;
}
else
{
m_busy = true;
}
long fileLength = getDownloadFileLenth (Url.c_str ());
if (fileLength <= 0)
{
printf ("get the file length error...");
return false;
}
// Create a file to save package.
if (Path.length() > 1 && Path.at(Path.length() - 1) != '/')
{
Path += '/';
}
const std::string outFileName = Path + fileName;
FILE *fp = fopen (outFileName.c_str (), "wb");
if (!fp)
{
emit finished(false);
return false;
}
long partSize = fileLength / threadNum;
for (int i = 0; i <= threadNum; i++)
{
tNode *pNode = new tNode ();
if (i < threadNum)
{
pNode->startPos = i * partSize;
pNode->endPos = (i + 1) * partSize - 1;
}
else
{
if (fileLength % threadNum != 0)
{
pNode->startPos = i * partSize;
pNode->endPos = fileLength - 1;
}
else
break;
}
CURL *curl = curl_easy_init ();
pNode->curl = curl;
pNode->fp = fp;
char range[64] = { 0 };
snprintf (range, sizeof (range), "%ld-%ld", pNode->startPos, pNode->endPos);
// Download pacakge
curl_easy_setopt (curl, CURLOPT_URL, Url.c_str ());
curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, writeFunc);
curl_easy_setopt (curl, CURLOPT_WRITEDATA, (void *) pNode);
curl_easy_setopt (curl, CURLOPT_NOPROGRESS, 0L);
if(m_vpProgressFunc.size() > i)
{
curl_easy_setopt (curl, CURLOPT_PROGRESSFUNCTION, m_vpProgressFunc[i]);
}
curl_easy_setopt (curl, CURLOPT_NOSIGNAL, 1L);
curl_easy_setopt (curl, CURLOPT_LOW_SPEED_LIMIT, 1L);
curl_easy_setopt (curl, CURLOPT_LOW_SPEED_TIME, 5L);
curl_easy_setopt (curl, CURLOPT_RANGE, range);
pthread_mutex_lock (&g_mutex);
threadCnt++;
pthread_mutex_unlock (&g_mutex);
int rc = pthread_create (&pNode->tid, nullptr, workThread, pNode);
}
while (threadCnt > 0)
{
sleep(1000);
}
fclose (fp);
printf ("download succed......\n");
emit finished(true);
m_busy = false;
return true;
}
void QLibCurl::sleep(int msec)
{
QEventLoop loop;//定义一个新的事件循环
QTimer::singleShot(msec, &loop, SLOT(quit()));//创建单次定时器,槽函数为事件循环的退出函数
loop.exec();//事件循环开始执行,程序会卡在这里,直到定时时间到,本循环被退出
}
int QLibCurl::nProgress0(void *ptr, double totalToDownload, double nowDownloaded, double totalToUpLoad, double nowUpLoaded)
{
Q_UNUSED(ptr)
Q_UNUSED(nowUpLoaded)
Q_UNUSED(totalToUpLoad)
m_pLibCurl->emit progress(static_cast<int>(nowDownloaded), static_cast<int>(totalToDownload), 0);
return 0;
}
int QLibCurl::nProgress1(void *ptr, double totalToDownload, double nowDownloaded, double totalToUpLoad, double nowUpLoaded)
{
Q_UNUSED(ptr)
Q_UNUSED(nowUpLoaded)
Q_UNUSED(totalToUpLoad)
m_pLibCurl->emit progress(static_cast<int>(nowDownloaded), static_cast<int>(totalToDownload), 1);
return 0;
}
int QLibCurl::nProgress2(void *ptr, double totalToDownload, double nowDownloaded, double totalToUpLoad, double nowUpLoaded)
{
Q_UNUSED(ptr)
Q_UNUSED(nowUpLoaded)
Q_UNUSED(totalToUpLoad)
m_pLibCurl->emit progress(static_cast<int>(nowDownloaded), static_cast<int>(totalToDownload), 2);
return 0;
}
int QLibCurl::nProgress3(void *ptr, double totalToDownload, double nowDownloaded, double totalToUpLoad, double nowUpLoaded)
{
Q_UNUSED(ptr)
Q_UNUSED(nowUpLoaded)
Q_UNUSED(totalToUpLoad)
m_pLibCurl->emit progress(static_cast<int>(nowDownloaded), static_cast<int>(totalToDownload), 3);
return 0;
}
long QLibCurl::getDownloadFileLenth(const char *url)
{
double downloadFileLenth = 0;
CURL *handle = curl_easy_init ();
curl_easy_setopt (handle, CURLOPT_URL, url);
curl_easy_setopt (handle, CURLOPT_HEADER, 1); //只需要header头
curl_easy_setopt (handle, CURLOPT_NOBODY, 1); //不需要body
if (curl_easy_perform (handle) == CURLE_OK)
{
curl_easy_getinfo (handle, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &downloadFileLenth);
}
else
{
downloadFileLenth = -1;
}
return downloadFileLenth;
}
size_t QLibCurl::writeFunc(void *ptr, size_t size, size_t nmemb, void *userdata)
{
tNode *node = (tNode *) userdata;
size_t written = 0;
pthread_mutex_lock (&g_mutex);
if (node->startPos + size * nmemb <= node->endPos)
{
fseek (node->fp, node->startPos, SEEK_SET);
written = fwrite (ptr, size, nmemb, node->fp);
node->startPos += size * nmemb;
}
else
{
fseek (node->fp, node->startPos, SEEK_SET);
written = fwrite (ptr, 1, node->endPos - node->startPos + 1, node->fp);
node->startPos = node->endPos;
}
pthread_mutex_unlock (&g_mutex);
return written;
}
void *QLibCurl::workThread(void *pData)
{
tNode *pNode = (tNode *) pData;
int res = curl_easy_perform (pNode->curl);
if (res != 0)
{
}
curl_easy_cleanup (pNode->curl);
pthread_mutex_lock (&g_mutex);
threadCnt--;
printf ("thred %ld exit\n", pNode->tid);
pthread_mutex_unlock (&g_mutex);
delete pNode;
pthread_exit (nullptr);
}
欢迎交流。
更多推荐
所有评论(0)