首页 > 其他分享 >https多线程下载代码

https多线程下载代码

时间:2024-03-23 17:23:11浏览次数:27  
标签:多线程 easy pFile double 代码 pCurl https curl include

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

  对应的.h头文件:

  

#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);
}

 

  

标签:多线程,easy,pFile,double,代码,pCurl,https,curl,include
From: https://www.cnblogs.com/JsonZhangAA/p/18091345

相关文章

  • Collections工具类,可以使用collections工具类对代码中的list进行分组
    /***根据活动id进行分组*key活动id*value活动id对应的商品id*/Map<Long,Set<Long>>collect=activitySkuList.stream().collect(Collectors.groupingBy(ActivitySku::getActivityId......
  • 代码随想录算法训练营第五十五天| ● 583. 两个字符串的删除操作 ● 72. 编辑距离
    两个字符串的删除操作 题目链接:583.两个字符串的删除操作-力扣(LeetCode)思路:第一次尝试用画图法,然后肉眼观察dp递归规律……但是dp[i][j]的含义还是参考昨天的思路,表示到此处需要删除多少个字符。classSolution{public:intminDistance(stringword1,stringword2......
  • 利用 Lambda 获取更简洁的代码
    本文演示了一个Java重构的真实示例,旨在实现更简洁的代码和更好的关注点分离。这个想法源于我在专业环境中编码的经验。从前在生产代码中当我处理持久化一些域数据的代码时,我最终得到了以下结果:publicvoidprocessMessage(InsuranceProductproduct)throwsException......
  • 前端报错 request to https://registry.npm.taobao.org/yorkie/download/yorkie-2.0.0
    前端npminstall报错:npmERR!requesttohttps://registry.npm.taobao.org/yorkie/download/yorkie-2.0.0.tgzfailed,reason:certificatehasexpired解决方式://1.清空缓存npmcacheclean--force//2.切换新源:npmconfigsetregistry镜像源npmconfig......
  • 远程代码执行
    远程代码执行一、什么是远程代码执行?远程代码执行RemoteCodeExecute远程命令执行RemoteCommandExecute由于程序中预留了执行代码或者命令的接口,并且提供了给用户使用的界面,导致被黑客利用,控制服务器。为什么要执行代码?网络设备的web管理界面自动化运维系统漏洞危......
  • 代码随想录算法训练营第3天 | 链表 |虚拟头哨兵
    链表理论基础链表节点的定义structListNode{intval;//节点上存储的元素ListNode*next;//指向下一个节点的指针ListNode(intx):val(x),next(NULL){}//节点的构造函数};==如果不自己定义构造函数,就无法通过ListNodep(5);来初始化203删除......
  • 代码随想录算法训练营day31 | leetcode 455. 分发饼干、376. 摆动序列、53. 最大子数
    目录贪心理论基础核心:题目链接:455.分发饼干-简单题目链接:376.摆动序列-中等题目链接:53.最大子数组和-中等贪心理论基础核心:由局部推全局最优题目链接:455.分发饼干-简单题目描述:假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。对每......
  • 没有运算结果,直接执行完所有代码
    以下代码错误的地方在于,把用户输入的值保存在了”three“这个变量里面,所以会导致代码并没有报错,但是没有两数之和的结果,直接打印出”非正确数字“。应该把两数的结果放在”operation“这个结果里面。1importjava.util.Scanner;23publicclassfirstClass{4pub......
  • https://github.com/google/adb-sync
    大致的实现方式:是一个python文件,在windows上就pythonadb-sync-R-t-n--dry-run/storage/emulated/0C:\a\b这样运行 其中本机系统的文件列表和修改时间获取就用os库(importos)手机上的文件列表和修改时间获取就用ls-al     https://blog.csdn.net/chabb/ar......
  • 基于ssm+vue.js的游戏销售系统附带文章和源代码设计说明文档ppt
    文章目录前言详细视频演示具体实现截图技术栈后端框架SSM前端框架Vue持久层框架MyBaits系统测试系统测试目的系统功能测试系统测试结论为什么选择我代码参考数据库参考源码获取前言......