C语言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 是支持断点续传

上一篇:宋宝华:用eBPF/bcc分析系统性能的一个简单案例


下一篇:nmcli管理无线网络