https多线程下载代码

这篇具有很好参考价值的文章主要介绍了https多线程下载代码。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

  这里使用了curl网络库和使用多线程来下载对应https链接的文件

  对应的.h头文件:

  文章来源地址https://www.toymoban.com/news/detail-842733.html

#pragma once

#include <iostream>
#include <fstream>
#include <curl/curl.h>
#include <pthread.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/types.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>

using namespace std;

#define  THREADS_NUMS  (10)

class  FileInfo
{
public:
    void * pFile;
    size_t offset;
    size_t endpos;
    char * pUrl;
    pthread_t  tid;
    size_t  used;
    FILE * file;
    size_t totalLen;
};

size_t  writeFile(void *pData, size_t dwSize, size_t dwMemb, void * pFile);
int progress_callback(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow);
void *  works(void * arg);
void sighandler_func(int arg);

class DownFile
{
    public:
        virtual bool downFile()=0;
};

class  HttpDownFile:public DownFile
{
public:
    HttpDownFile(char * pUrl, char * pFile):m_pUrl(pUrl),m_pFile(pFile){
        if(SIG_ERR==signal(SIGINT,sighandler_func))
        {
            cout<<"signal error"<<endl;
        }
    }

    virtual bool downFile();

private:
    double  getFileLength();

    long lastLen=0;
    char * m_pUrl;  //需要下载的http连接
    char * m_pFile; //本地存储文件的位置
};

其中,

writeFile函数主要处理将服务器上的文件下载到本地上。对应CURLOPT_WRITEFUNCTION

progress_callback函数用来计算下载进度。对应CURLOPT_PROGRESSFUNCTION

sighandler_func函数处理ctrl+c后,存储当前的下载进度
works函数,各线程的处理函数
HttpDownFile::getFileLength 用来获取需要下载文件的大小
 
这里使用了mmap(内存映射)来让各线程同步写本地放置下载文件的文件。

具体的函数实现如下:

#pragma once

#include "advanDown.h"

FileInfo m_cFiles[THREADS_NUMS+1];
long dwLen=0;

double  HttpDownFile::getFileLength()
{
    CURL * pCurl=curl_easy_init();
    if(NULL==pCurl)
    {
        cout<<"curl_easy_init error!"<<endl;
        return false;
    }

    curl_easy_setopt(pCurl,CURLOPT_URL,m_pUrl);
    curl_easy_setopt(pCurl,CURLOPT_HEADER ,1);
    curl_easy_setopt(pCurl,CURLOPT_NOBODY ,1);

    CURLcode tRet=curl_easy_perform(pCurl);

    if(0!=tRet)
    {
        cout<<"curl_easy_perform error"<<endl;
        return false;
    }

    double  duLd=0;
    tRet=curl_easy_getinfo(pCurl,CURLINFO_CONTENT_LENGTH_DOWNLOAD,&duLd);

    curl_easy_cleanup(pCurl);

    return duLd;
}

size_t  writeFile(void *pData, size_t dwSize, size_t dwMemb, void * pFile)
{
    FileInfo * pFileInfo=(FileInfo *)pFile;
    cout<<"id: "<<pFileInfo->tid<<" offset: "<<pFileInfo->offset<<endl;

    memcpy((char *)pFileInfo->pFile+pFileInfo->offset,(char *)pData,dwSize*dwMemb);

    pFileInfo->offset+=dwSize*dwMemb;
    pFileInfo->used+=dwSize*dwMemb;

    return dwSize*dwMemb;
}

int progress_callback(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow){
    if (dltotal != 0)
    {
        //printf("%lf / %lf (%lf %%)\n", dlnow, dltotal, dlnow*100.0 / dltotal);
        long totalUsedLen=0;
        //long totalLen=0;
        for(int i=0;i<THREADS_NUMS+1;i++)
        {
            totalUsedLen+=m_cFiles[i].used;
            totalUsedLen+=m_cFiles[i].totalLen;
        }


        printf("%ld / %ld (%ld %%)\n",totalUsedLen,dwLen,totalUsedLen*100/dwLen);
    }
    return 0;
}

void *  works(void * arg)
{
    FileInfo  * pFile=(FileInfo *)arg;

    CURL * pCurl=curl_easy_init();
    if(NULL==pCurl)
    {
        cout<<"curl_easy_init error!"<<endl;
        return NULL;
    }

    if(pFile->file)
    {
        cout<<"hello"<<endl;
        fscanf(pFile->file,"%ld-%ld-%ld",&pFile->offset,&pFile->endpos,&pFile->totalLen);
    }


    if(pFile->offset>=pFile->endpos-1)
    {
        cout<<pFile->tid<<"  already downed: "<<pFile->offset<<"--"<<pFile->endpos<<endl;
        return NULL;
    }

    char buffer[64]={0};
    snprintf(buffer,64,"%ld-%ld",pFile->offset,pFile->endpos);

    cout<<"offset/endpos: "<<pFile->offset<<"--"<<pFile->endpos<<endl;

    //cout<<cFile.tid<<": "<<cFile.offset<<" -- "<<cFile.endpos<<endl;

    curl_easy_setopt(pCurl,CURLOPT_URL,pFile->pUrl);
    curl_easy_setopt(pCurl,CURLOPT_WRITEFUNCTION,writeFile);
    curl_easy_setopt(pCurl,CURLOPT_WRITEDATA ,pFile);
    curl_easy_setopt(pCurl,CURLOPT_RANGE,buffer);
    curl_easy_setopt(pCurl,CURLOPT_NOPROGRESS ,0L);
    curl_easy_setopt(pCurl,CURLOPT_PROGRESSFUNCTION,progress_callback);
    curl_easy_setopt(pCurl,CURLOPT_PROGRESSDATA,pFile);


    CURLcode tRet=curl_easy_perform(pCurl);

    if(0!=tRet)
    {
        cout<<"curl_easy_perform error"<<endl;
        return NULL;
    }

    curl_easy_cleanup(pCurl);

    return NULL;
}

bool HttpDownFile::downFile()
{
    dwLen=(long)getFileLength();

    cout<<"dwLen: "<<dwLen<<endl;

    int fd=open(m_pFile,O_RDWR|O_CREAT,S_IRUSR|S_IWUSR);

    if(fd==-1)
    {
        cout<<"open failed"<<endl;
        return false;
    }

    if(lseek(fd,dwLen,SEEK_SET)==-1)
    {
        cout<<"lseek failed"<<endl;
        close(fd);
        return false;
    }

    if(write(fd,"",1)!=1)
    {
        cout<<"write failed"<<endl;
        close(fd);
        return false;
    }

    char * filePos=(char *)mmap(NULL,dwLen,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);

    if(filePos==MAP_FAILED)
    {
        close(fd);

        cout<<"mmap failed: "<<errno<<endl;
        return false;
    }

    int slice=dwLen/THREADS_NUMS;
    FILE * file=fopen("downTemp.txt","r+");

    //10 threads
    for(int i=0;i<THREADS_NUMS+1;i++)
    {
        m_cFiles[i].offset=i*slice;
        m_cFiles[i].pUrl=m_pUrl;
        m_cFiles[i].pFile=filePos;
        //cFiles[i].used=0;
        m_cFiles[i].file=file;
        if(i==THREADS_NUMS)
        {
            m_cFiles[i].endpos=dwLen-1;
            //cFiles[i].totalLen=cFiles[i].endpos-cFiles[i].offset+1;
        }
        else
        {
            m_cFiles[i].endpos=(i+1)*slice-1;
            //cFiles[i].totalLen=slice;
        }
        pthread_create(&m_cFiles[i].tid,NULL,works,&m_cFiles[i]);
        usleep(1);
    }

    for(int i=0;i<THREADS_NUMS+1;i++)
    {
        pthread_join(m_cFiles[i].tid,NULL);
    }

    close(fd);

    munmap(filePos,dwLen);


    return true;
}

void sighandler_func(int arg)
{
    cout<<"arg: "<<arg<<endl;
    int fd=open("downTemp.txt",O_RDWR|O_CREAT,S_IRUSR|S_IWUSR);
    for(int i=0;i<THREADS_NUMS+1;i++)
    {
        m_cFiles[i].totalLen=m_cFiles[i].used;
        //cout<<"used: "<<cFiles[i].used<<"/"<<cFiles[i].totalLen<<endl;
        char buffer[64]={0};
        snprintf(buffer,64,"%ld-%ld-%ld\n",m_cFiles[i].offset,m_cFiles[i].endpos,m_cFiles[i].totalLen);
        write(fd,buffer,strlen(buffer));
    }

    close(fd);

    exit(-1);
}

 

  

到了这里,关于https多线程下载代码的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 因为懒,我用了“低代码”打下手

    一、前言 二、工具介绍 三、平台特点 四、如何使用JNPF? 五、低代码平台的选择参考 六、总结 「一个优秀的开发者,一定是会利用各种工具来提升自己的开发效率。」 前段时间,体验了很多国内前沿的低代码平台,在csdn上也看到很多优秀的低代码平台文章分享,自己尝试

    2024年02月09日
    浏览(29)
  • 【Linux命令详解 | wget命令】 wget命令用于从网络下载文件,支持HTTP、HTTPS和FTP协议

    在编程世界中,处理网络资源是一项关键任务,而 wget 命令就是一位可靠的助手。 wget (全名为“Web Get”)是一种用于从网络下载文件的工具,它能够处理多种协议,包括HTTP、HTTPS和FTP。作为一个博主,我们可以利用 wget 命令来获取文件、备份网站内容、自动下载资源等。

    2024年02月12日
    浏览(34)
  • 用了这款插件,零代码基础也能写代码你信吗?

    使用过 chatGPT 的同学,可能都会有过这样的经历?遇到代码不会的问题,本能的就会去求助 chatGPT ,然后并根据chatGPT的回答去优化代码。但是,没了梯子的话, chatGPT 是不是也帮不上忙了?还是只有我是这样的情况 ̄□ ̄|| 当然,这也让我偶然发现这个插件,对于我这种

    2024年02月06日
    浏览(33)
  • 【git】pip install git+https://github.com/xxx/xxx替换成本地下载编译安装解决网络超时问题

    目录 🌑🌑 背景  🌒 🌒作用 🌔🌔 问题 🌔🌔解决方案  🌙方法一 🌙方法二 🌝🌝我的解决方案 整理不易,欢迎一键三连!!! 送你们一条美丽的--分割线--         通常在安装某些模型或者模块时,通常最方便的方式就是通过 pip install git+https://github.com/xxx/xxx 的方式

    2024年02月04日
    浏览(34)
  • 从系统设计到撸代码?我用了这些方法和工具

    大家好,我是老猫。今天和大家分享一下程序员日常的绘图思路,以及一些老猫日常使用的绘图工具。 我们在进行系统设计的时候,为了更加具象地呈现系统的轮廓以及各个组件或者系统之间的关系和边界以及工作流程。我们就会画逻辑架构图,模块图、流程图、时序图等等

    2024年04月22日
    浏览(25)
  • 用了这款 IDEA 神器,领导都夸我代码写得好!

    CheckStyle作为检验代码规范的插件,除了可以使用配置默认给定的开发规范,如Sun的,Google的开发规范啊,也可以导入像阿里的开发规范的插件。 事实上,每一个公司都存在不同的开发规范要求,所以大部分公司会给定自己的check规范,一般导入给定的 checkstyle.xml 文件即可实

    2024年02月16日
    浏览(35)
  • 基于curl 使用http多线程下载大文件

    如需完整代码,可评论区留言

    2024年02月04日
    浏览(46)
  • 计算机网络编程 | 并发服务器代码实现(多进程/多线程)

    欢迎关注博主 Mindtechnist 或加入【Linux C/C++/Python社区】一起学习和分享Linux、C、C++、Python、Matlab,机器人运动控制、多机器人协作,智能优化算法,滤波估计、多传感器信息融合,机器学习,人工智能等相关领域的知识和技术。 专栏:《网络编程》 当涉及到构建高性能的服务

    2024年02月08日
    浏览(46)
  • Git 使用https克隆代码

    在管理Git项目上,很多时候都是直接使用https url克隆到本地,当然也有有些人使用SSH url克隆到本地。 这两种方式的主要区别在于: 使用https url克隆对初学者来说会比较方便,复制https url然后到git Bash里面直接用clone命令克隆到本地就好了,但是每次fetch和push代码都需要输入账

    2024年02月13日
    浏览(56)
  • Go源码实现使用多线程并发下载大文件的功能

    摘要:Go语言编码实现了使用多线程并发下载文件的功能。 1. 获取系统的CPU核心数量,并将其作为线程数的参考值,并打印出来。 2. 定义要下载的文件的URL、线程数和输出文件名。 3. 使用`getFileSize()`函数获取文件大小,并打印出来。 4. 根据文件大小和线程数计算文件块大小

    2024年02月08日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包