ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

C语言CURL网络连接 为了下载做准备

2022-03-02 22:32:10  阅读:214  来源: 互联网

标签:easy url request C语言 range context 网络连接 CURL curl


难点补充
1

oid SendRequest(RequestContext *request_context) {
  if (request_context->is_running) {
    PRINTLNF("request already running ....");
    return;
  }

  CURL *curl = curl_easy_init();
  if (!curl) {
    request_context->curl_code = -1;
    return;
  }
    //参数配置
  curl_easy_setopt(curl, CURLOPT_URL, request_context->url);
  //对于http 返回请求302 重定向做一处理
  curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
  //这里解析文件名称 文件大小 文件!是什么
  curl_easy_setopt(curl, CURLOPT_NOBODY, request_context->header_only);

  curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, CurlHeaderFunction);
  curl_easy_setopt(curl, CURLOPT_HEADERDATA, request_context);

  curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CurlBodyFunction);
  curl_easy_setopt(curl, CURLOPT_WRITEDATA, request_context);
    //进度回调
  if (request_context->request->progress_callback) {
    curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L);
    curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, CurlProgressFunction);
    curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, request_context);
  }
    //断点续传
  char content_range[40];
  if (request_context->range_start >= 0 && request_context->range_end >= 0) {
      //先下载一部分
    //9223372036854775808-9223372036854775808 | 838TB
    snprintf(content_range, 40, "%llu-%llu", request_context->range_start, request_context->range_end);
  } else if (request_context->range_start >= 0) {
      //暂停后开始
    //9223372036854775808- | 838TB
    snprintf(content_range, 40, "%llu-", request_context->range_start);
  } else if (request_context->range_end >= 0) {
    //-9223372036854775808 | 838TB
    snprintf(content_range, 40, "-%llu", request_context->range_end);
  } else {
    // no range request.
    content_range[0] = 0;
  }

  if (content_range[0] > 0) {
    PRINTLNF("content-range: %s", content_range);
    CURLcode code = curl_easy_setopt(curl, CURLOPT_RANGE, content_range);
  }

  curl_easy_setopt(curl, CURLOPT_CAINFO, "cacert.pem");
  curl_easy_setopt(curl, CURLOPT_CAPATH, "cacert.pem");

  request_context->curl = curl;
  request_context->is_running = 1;
  //请求得到返回值  调用这句话的时候 请求
  request_context->curl_code = curl_easy_perform(curl);
  request_context->curl = NULL;
  request_context->is_running = 0;

  curl_easy_getinfo(curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD_T, &request_context->file_size);
  curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &request_context->response_code);
 // 找不到文件名  header里面没有对应的字段  解析不出来字段 就根据URL 解析
  if (request_context->header_only && !request_context->output_filename) {
    RetrieveOutputNameFromUrl(request_context);
  }

  if (request_context->output_stream) {
    fclose(request_context->output_stream);
    request_context->output_stream = NULL;
  }

  curl_easy_cleanup(curl);
}

对于断点设定就是结构体里面初始化两个变量 然后根据里面的值进行判断下载 一般就是暂停保存一下 然后开始的时候读取那个点

typedef struct RequestContext {
  Request *request;

  char *url;
  char *download_directory;

  int header_only;

  int64_t range_start;
  int64_t range_end;

还有就是多线程下载要注意的问题

RequestContext *CreateRequestContext(Request *request, const char *url, const char *directory) {
  CREATE_OBJECT_CLEANED(RequestContext, context);
  context->request = request;
  //复制一下为多线程做准备  url 是复制一份  以防止多线程私有栈被释放
  context->url = strdup(url);
  context->download_directory = strdup(directory);
  context->file_size = 0;
  context->range_start = -1;
  context->range_end = -1;

  context->is_running = 0;
  return context;
}

header中找不到字段的话去url 里面找

 // 找不到文件名  header里面没有对应的字段  解析不出来字段 就根据URL 解析
  if (request_context->header_only && !request_context->output_filename) {
    RetrieveOutputNameFromUrl(request_context);
  }
// header 里面没有字段 就根据 url 解析  就是解析 task 里面的最后一个文件名
static int RetrieveOutputNameFromUrl(RequestContext *context) {
  int result = RESULT_OK;

  char output_filename[1024];
  char const *url = context->url;
  // http://www.bennyhuo.com/testdata/三国演义.txt?param=1
  // http://www.bennyhuo.com/testdata/三国演义.txt#chapter1
  // http://www.bennyhuo.com/testdata/%E4%B8%89%E5%9B%BD%E6%BC%94%E4%B9%89.txt?param=1
  url = strrchr(url, '/');
  url++;

  int i = 0;
  while (*url != '\0' && *url != '?' && *url != '#') {
    output_filename[i++] = *url++;
  }

  output_filename[i] = '\0';
  char *url_decoded_filename = curl_easy_unescape(context->curl, output_filename, 0, NULL);
  context->output_filename = strdup(url_decoded_filename);
  curl_free(url_decoded_filename);
  return result;
}

printf("%.*s", (int) buffer_size, buffer); 传入点 * 自己设定字符串大小
在http 的url 协议中是不会自己传递 汉字的都是编码后的结果 所以拿到的都是编码后的内容 要进行解码
strdup()在内部调用了malloc()为变量分配内存,不需要使用返回的字符串时,需要用free()释放相应的内存空间,否则会造成内存泄漏。

static int RetrieveOutputNameFromUrl(RequestContext *context) {
  int result = RESULT_OK;

  char output_filename[1024];
  char const *url = context->url;
  // http://www.bennyhuo.com/testdata/三国演义.txt?param=1
  // http://www.bennyhuo.com/testdata/三国演义.txt#chapter1
  // http://www.bennyhuo.com/testdata/%E4%B8%89%E5%9B%BD%E6%BC%94%E4%B9%89.txt?param=1
  url = strrchr(url, '/');
  url++;

  int i = 0;
  while (*url != '\0' && *url != '?' && *url != '#') {
    output_filename[i++] = *url++;
  }

  output_filename[i] = '\0';
  char *url_decoded_filename = curl_easy_unescape(context->curl, output_filename, 0, NULL);
  context->output_filename = strdup(url_decoded_filename);
  curl_free(url_decoded_filename);
  return result;

如果Http 返回值是206 是支持断点续传

标签:easy,url,request,C语言,range,context,网络连接,CURL,curl
来源: https://blog.csdn.net/qq_33329316/article/details/123231425

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有