程序不显示文件的下载速度和大小(curl)

时间:2015-01-03 15:33:00

标签: c curl download

我在Ubuntu上遇到卷曲问题。我希望它显示下载文件的下载速度和大小。我已经声明了double * size和double * speedd以及CURL * curl。我一直在分段错误。程序编译成“文件下载”的时刻。它还应该告诉我来自CURLINFO_SIZE_DOWNLOAD和CURLINFO_SPEED_DOWNLOAD的信息。请帮忙。

#define CURL_STATICLIB
#include <stdio.h>
#include <curl/curl.h>
#include <string.h>
#include <stdlib.h>

size_t write_data(void *ptr, size_t size, size_t nmemb, FILE *stream)
{
    size_t written;
    written = fwrite(ptr, size, nmemb, stream);
    return written;
}

int main(void)
{
    CURL *curl;
    FILE *fp;
    CURLcode res;
    FILE *stream = stdout;
    int x;
    char y[1024];
    double* sized;
    double* speedd;
    char* name = calloc(1, 1024);
    char* outfilename;
    char* path_pdf = "/home/user/Desktop/%s.pdf";
    char* path_jpg = "/home/user/Desktop/%s.jpg";
    char* path_txt = "/home/user/Desktop/%s.txt";
    char* path_mp3 = "/home/user/Desktop/%s.mp3";
    char* path_avi = "/home/user/Desktop/%s.avi";
    printf("Enter file url: \n"); // for example http://oi58.tinypic.com/15nk3de.jpg
    scanf ("%s",y);
    char *url = y;
    printf("Type name of file \n");
    scanf("%s",name);
    char *result_pdf = malloc(strlen(path_pdf) - 2 + strlen(name) + 1);
    sprintf(result_pdf, path_pdf, name);
    char *result_jpg = malloc(strlen(path_jpg) - 2 + strlen(name) + 1);
    sprintf(result_jpg, path_jpg, name);
    char *result_txt = malloc(strlen(path_txt) - 2 + strlen(name) + 1);
    sprintf(result_txt, path_txt, name);
    char *result_mp3 = malloc(strlen(path_mp3) - 2 + strlen(name) + 1);
    sprintf(result_mp3, path_mp3, name);
    char *result_avi = malloc(strlen(path_avi) - 2 + strlen(name) + 1);
    sprintf(result_avi, path_avi, name);
    printf("Choose type of file:\n [0] - pdf\n [1] - jpg\n [2] - txt\n [3] - mp3\n [4] - avi\n "); //choose 1
    scanf("%d",&x);
    switch(x){
    case 0:
    outfilename = result_pdf;
    break;
    case 1:
    outfilename = result_jpg;
    break;
    case 2:
    outfilename = result_txt;
    break;
    case 3:
    outfilename = result_mp3;
    break;
    case 4:
    outfilename = result_avi;
    break;

}
    curl = curl_easy_init();
    if (curl)
    {
        fp = fopen(outfilename,"wb");
        curl_easy_setopt(curl, CURLOPT_URL, url);
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
        printf("Download started!\n\n");
        curl_easy_setopt (curl, CURLOPT_VERBOSE, 1L);
        res = curl_easy_perform(curl);
        if(res == CURLE_OK) {
        printf("File downloaded!\n\n");}
        else {
        printf("Transfer failed!");}
        curl_easy_getinfo(curl,CURLINFO_SIZE_DOWNLOAD,&sized);
        fprintf(stream,"%.3f \n", sized);
        curl_easy_getinfo(curl,CURLINFO_SPEED_DOWNLOAD,&speedd);
        fprintf(stream, "%.3f \n", speedd);
        curl_easy_cleanup(curl);
        fclose(fp);
    }
    return 0;

}

1 个答案:

答案 0 :(得分:1)

您在问题中提供的代码存在一些问题:

  1. 您未加入stdlib.h

  2. name未分配

  3. 您尚未为uri的路径部分分配存储空间的空间。当您调用scanf(3)来读取路径名时,它会尝试将其存储到name引用的内存位置。由于name未初始化,指针的值未定义。这会导致分段错误。

    name分配内存,或者从指向数组的指针更改类型,大小合适。

     char *name = calloc(1, 1024);
     printf("Type name of file \n");
     scanf("%s",name);
    

    或者

     char name[1024];
     printf("Type name of file \n");
     scanf("%s",name);
    

    两者都可能适合您的需求。但是,请注意这些方法会引入堆或堆栈溢出错误,因为scanf(3)不执行边界检查。这类事情的通常模式是使用fgets(3)来读取输入行,使用sscanf(3)来标记它。在这种情况下,您实际上只需要fgets(3)

    使用gets(3)

    1. 您没有成功打印下载信息。
    2. 在您的代码中,您只能在失败时从cURL打印出状态信息:

      if (res == CURLE_OK) {
          printf("File downloaded!\n\n");
      } else {
          printf("Transfer failed!");}
          curl_easy_getinfo(curl,CURLINFO_SIZE_DOWNLOAD,sized);
          curl_easy_getinfo(curl,CURLINFO_SPEED_DOWNLOAD,speedd);
          curl_easy_cleanup(curl);
          fclose(fp);
      }
      

      相反,我认为你的意思是:

      if (res == CURLE_OK) {
          printf("File downloaded!\n\n");
      } else {
          printf("Transfer failed!");}
      }
      
      curl_easy_getinfo(curl,CURLINFO_SIZE_DOWNLOAD,sized);
      curl_easy_getinfo(curl,CURLINFO_SPEED_DOWNLOAD,speedd);
      curl_easy_cleanup(curl);
      fclose(fp);
      

      我猜测这个问题的原因是因为你的代码风格。看起来你至少对C来说是半新的。用一致的风格写作会提高你的代码可读性并帮助你避免这样的错误。你坚持使用什么样的风格并不重要。

      1. 您的程序的行为是出乎意料的,它会增加代码大小
      2. 你的程序架构有点迟钝。允许用户在命令行上指定参数更为常见。在这种情况下,您可以选择命名输出文件,也可以选择命名源URI。

        即使你这样做是为了学习标准库,最好还是继续让你的实现以更加预期的方式运行。另请参见getopt(3)联机帮助页。您可能会发现,一旦执行此操作,您的程序将缩小一半。

        较小的程序是一个更好的程序。

        1. 您将未定义的指针值传递给curl_easy_getinfo
        2. 你已宣布

          double* sized;
          double* speedd;
          

          但尚未为这些提供存储空间。当您致电curl_easy_getinfo时,它会崩溃。您在评论中提到您通过将地址传递给curl_easy_getinfo来解决此问题。这会停止崩溃,因为您已为地址提供了存储空间。但是,如果您要尝试打印该信息,您将无法获得任何结果,或者再次崩溃。

          相反,你想要的是:

          double sized;
          double speedd;
          ...
          curl_easy_getinfo(curl,CURLINFO_SIZE_DOWNLOAD,&sized);
          curl_easy_getinfo(curl,CURLINFO_SPEED_DOWNLOAD,&speedd);
          
          1. 您无法在任何地方打印出尺寸或速度。
          2. 一旦获得它们,就不会在main功能结束时打印尺寸或速度。您需要将它们打印出来,如:

            printf("Size: %g KB\nSpeed: %g KB/s\n", sized / 1024., speedd / 1024.);
            

            通过这些更改,这是完整运行的输出:

            Enter file url:
            http://oi58.tinypic.com/15nk3de.jpg
            Type name of file
            foo.jpg
            Choose type of file:
             [0] - pdf
             [1] - jpg
             [2] - txt
             [3] - mp3
             [4] - avi
             1
            Download started!
            
            * Hostname was NOT found in DNS cache
            *   Trying 209.17.68.209...
            * Connected to oi58.tinypic.com (209.17.68.209) port 80 (#0)
            > GET /15nk3de.jpg HTTP/1.1
            Host: oi58.tinypic.com
            Accept: */*
            
            < HTTP/1.1 200 OK
            * Server Apache is not blacklisted
            < Server: Apache
            < Last-Modified: Thu, 13 Feb 2014 19:51:01 GMT
            < ETag: "1d7a5-4f24f024dc8be"
            < Cache-Control: max-age=21600
            < Expires: Sun, 04 Jan 2015 00:02:56 GMT
            < Content-Type: image/jpeg
            < Content-Length: 120741
            < Accept-Ranges: bytes
            < Date: Sat, 03 Jan 2015 19:24:19 GMT
            < X-Varnish: 1269536769 1268437896
            < Age: 4883
            < Via: 1.1 varnish
            < Connection: keep-alive
            < X-Varnish-Server: den2tpv65
            < X-Cache: HIT
            <
            * Connection #0 to host oi58.tinypic.com left intact
            File downloaded!
            
            Size: 117.911 KB
            Speed: 169.138 KB/s