【文件分片下载 libcurl】

简介: 【文件分片下载 libcurl】
// gcc -o multi_download multi_download.c -lcurl
#include <stdio.h>
#include <unistd.h>
#include <curl/curl.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>
#include <signal.h>
// fork();
struct fileInfo {
  const char *url;
  char *fileptr;
  int offset; //  start 
  int end;   // end
  pthread_t thid;
  double download; // 
  double totalDownload;
  FILE *recordfile;
};
#define THREAD_NUM    10
struct fileInfo **pInfoTable;
double downloadFileLength = 0;
// fwrite(fp, size, count, buf);
// libcurl
// 1.  fwrite/write
// mmap 
size_t writeFunc(void *ptr, size_t size, size_t memb, void *userdata) {
  // --> ptr
  struct fileInfo *info = (struct fileInfo *)userdata;
  //printf("writeFunc: %ld\n", size * memb);
  memcpy(info->fileptr + info->offset, ptr, size * memb);
  info->offset += size * memb;
  return size * memb;
}
// 
int progressFunc(void *userdata, double totalDownload, double nowDownload, double totalUpload, double nowUpload) {
  int percent = 0;
  static int print = 1;
  struct fileInfo *info = (struct fileInfo*)userdata;
  info->download = nowDownload;
  info->totalDownload = totalDownload;
  // save 
  if (totalDownload > 0) {
    int i = 0;
    double allDownload = 0;
    double total = 0;
    for (i = 0;i <= THREAD_NUM;i ++) {
      allDownload += pInfoTable[i]->download;
      total += pInfoTable[i]->totalDownload;
    }
    percent = (int)(allDownload / total * 100);
  }
  if (percent == print) {
    printf("threadid: %ld, percent: %d%%\n", info->thid, percent);
    print += 1;
  }
  return 0;
}
//
double getDownloadFileLength(const char *url) {
  CURL *curl = curl_easy_init();
  //printf("url: %s\n", url);
  curl_easy_setopt(curl, CURLOPT_URL, url);
  //curl_easy_setopt(curl, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36");
  curl_easy_setopt(curl, CURLOPT_HEADER, 1);
  curl_easy_setopt(curl, CURLOPT_NOBODY, 1);
// 111
  CURLcode res = curl_easy_perform(curl);
  if (res == CURLE_OK) {
    printf("downloadFileLength success\n");
    curl_easy_getinfo(curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &downloadFileLength);
  } else {
    printf("downloadFileLength error\n");
    downloadFileLength = -1;
  }
// 2222
  curl_easy_cleanup(curl);
  return downloadFileLength;
}
int recordnum = 0;
// curl
// 0 - 11
// multi
void *worker(void *arg) {
  struct fileInfo *info = (struct fileInfo*)arg;
  char range[64] = {0};
  // mutex_lock
  if (info->recordfile) {
    fscanf(info->recordfile, "%d-%d", &info->offset, &info->end);
  }
  // mutex_unlock
  if (info->offset > info->end) return NULL;
  snprintf(range, 64, "%d-%d", info->offset, info->end);
  //printf("threadid: %ld, download from: %d to: %d\n", info->thid, info->offset, info->end);
  // curl --> 
  CURL *curl = curl_easy_init();
  curl_easy_setopt(curl, CURLOPT_URL, info->url); // url
  curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeFunc); // save
  curl_easy_setopt(curl, CURLOPT_WRITEDATA, info); 
  curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L); // progress
  curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, progressFunc);
  curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, info);
  curl_easy_setopt(curl, CURLOPT_RANGE, range);
  // http range 
// 111
// multicurl 
  CURLcode res = curl_easy_perform(curl);
  if (res != CURLE_OK) {
    printf("res %d\n", res);
  }
// 2222
  curl_easy_cleanup(curl);
  return NULL;
}
// https://releases.ubuntu.com/22.04/ubuntu-22.04.2-live-server-amd64.iso.zsync
// ubuntu.zsync.backup
int download(const char *url, const char *filename) {
  //
  long fileLength = getDownloadFileLength(url);
  printf("downloadFileLength: %ld\n", fileLength);
  // write
  int fd = open(filename, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); // 
  if (fd == -1) {
    return -1;
  }
  if (-1 == lseek(fd, fileLength-1, SEEK_SET)) {
    perror("lseek");
    close(fd);
    return -1;
  }
  if (1 != write(fd, "", 1)) {
    perror("write");
    close(fd);
    return -1;
  }
  char *fileptr = (char *)mmap(NULL, fileLength, PROT_READ| PROT_WRITE, MAP_SHARED, fd, 0);
  if (fileptr == MAP_FAILED) {
    perror("mmap");
    close(fd);
    return -1;
  }
// fileLength 2014, 11
  FILE *fp = fopen("a.txt", "r");
// 0 99
// 100 199
// 200 299
// 300 399
// .....
// 1000 1023
  // thread arg
  int i = 0;
  long partSize = fileLength / THREAD_NUM;
  struct fileInfo *info[THREAD_NUM+1] = {NULL};
  for (i = 0;i <= THREAD_NUM;i ++) {
    info[i] = (struct fileInfo*)malloc(sizeof(struct fileInfo));
    memset(info[i], 0, sizeof(struct fileInfo));
    info[i]->offset = i * partSize;
    if (i < THREAD_NUM) {
      info[i]->end = (i+1) * partSize - 1;
    } else {
      info[i]->end = fileLength - 1;
    }
    info[i]->fileptr = fileptr;
    info[i]->url = url;
    info[i]->download = 0;
    info[i]->recordfile = fp;
  }
  pInfoTable = info;
  //pthread_t thid[THREAD_NUM+1] = {0};
  for (i = 0;i <= THREAD_NUM;i ++) {
    pthread_create(&(info[i]->thid), NULL, worker, info[i]);
    usleep(1);
  }
  for (i = 0;i <= THREAD_NUM;i ++) {
    pthread_join(info[i]->thid, NULL);
  }
  for (i = 0;i <= THREAD_NUM;i ++) {    
    free(info[i]);
  }
  if (fp)
    fclose(fp);
  munmap(fileptr, fileLength);
  close(fd);
  return 0;
}
//
void signal_handler(int signum) {
  printf("signum: %d\n", signum);
  //unlink("a.txt");
// save --> 
  int fd = open("a.txt",  O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
  if (fd == -1) {
    exit(1);
  }
  int i = 0;
  for (i = 0;i <= THREAD_NUM;i ++) {
    char range[64] = {0};
    snprintf(range, 64, "%d-%d\r\n", pInfoTable[i]->offset, pInfoTable[i]->end);
    write(fd, range, strlen(range));
  }
  close(fd);
  exit(1);
}
// multi_download  https://releases.ubuntu.com/22.04/ubuntu-22.04.2-live-server-amd64.iso.zsync  ubuntu.zsync
int main(int argc, const char *argv[]) {
  if (argc != 3) {
    printf("arg error\n");
    return -1;
  }
  if (SIG_ERR == signal(SIGINT, signal_handler)) {
    perror("signal");
    return -1;
  }
  return download(argv[1], argv[2]);
}
相关文章
|
6月前
|
PHP
PHP遍历文件并同步上传到服务器
在进行网站迁移时,由于原网站的图片文件过多,采用打包下载再上传的方式耗时过长,且尝试使用FTP工具从旧服务器传输至新服务器时失败。为解决此问题,特使用PHP编写了一款工具,该工具能扫描指定目录下的所有`.webp`图像文件,并将其上传至新的服务器,极大地提高了迁移效率。
121 16
|
PHP
PHP多文件分片压缩下载实现的详细介绍(二)
在上一篇博客中写了一个先压缩后分片下载的demo,但是存在一定的缺点,本篇介绍的是先分片然后放入压缩包最后再分片下载
111 0
|
XML 前端开发 JavaScript
PHP多文件压缩并分片下载文件详细介绍,附上完整代码
有时我们经常需要压缩下载多个文件,我这里主要采用在fastadmin框架中添加了一个表格自定义按钮,并为按钮绑定相应的事件来实现。
282 0
|
Linux
Linux常用的压缩与解压
1、gzip压缩解压 因为都是系统自带的我们不需要安装; ls 看一下目录当前的文件,创建一个 touch 123.txt 文件; 原文件消失,压缩解压 gzip 进行压缩,(“ gzip 123.txt ”),这样就压缩完毕了; gzip 进行解压,(“ gzip -d 123.txt.gz”),这样就解压完毕了; 原文件保留,gzip -k 123.txt、gzip -dk 123.txt.gz ; 2、bzip2压缩解压 因为都是系统自带的我们不需要安装; 原文件消失,压缩解压 bzip2进行压缩,(“ bzip2 123.txt ”),这样就压缩完毕了; bzip2 进行解压,(“
98 0
|
XML JSON 搜索推荐
PHP ZipArchive 大文件分片下载压缩 支持断点续传
PHP ZipArchive 大文件分片下载压缩 支持断点续传
202 0
|
JavaScript 数据格式 XML
libcurl上传文件
libcurl参数很多,一不小心就容易遇到问题。曾经就遇到过一个很蛋疼的问题:libcurl断点下载>>   这里主要汇总一下,libcurl上传的二种方式: 1、直接上传文件,类似form表单,>   直接上传文件: struct curl_httppost *fo...
1487 0
|
JavaScript Windows
nodejs版本大文件之断点下载
由于只是做个测试,这里使用了expresss简单搭建了个后台服务,提供文件断点下载。
nodejs版本大文件之断点下载
|
网络安全 数据安全/隐私保护 Windows