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



我在 Ubuntu 上使用 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] - pdfn [1] - jpgn [2] - txtn [3] - mp3n [4] - avin "); //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!nn");
        curl_easy_setopt (curl, CURLOPT_VERBOSE, 1L);
        res = curl_easy_perform(curl);
        if(res == CURLE_OK) {
        printf("File downloaded!nn");}
        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. 您不包括stdlib.h .

  2. 未分配name

尚未分配空间来存储 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. 您没有打印成功的下载信息。

在代码中,仅在失败时从 cURL 打印出状态信息:

if (res == CURLE_OK) {
    printf("File downloaded!nn");
} 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!nn");
} 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. 程序的行为出乎意料,从而增大了代码大小

程序的体系结构有点迟钝。允许用户在命令行上指定参数更为常见。在这种情况下,可以选择命名输出文件,也可以选择命名源 URI。

即使您这样做是为了学习标准库,也最好继续您的实现以更预期的方式运行。另请参阅getopt(3)手册页。您可能会发现,一旦执行此操作,程序的大小就会缩小大约一半。

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

  1. 您正在将未定义的指针值传递到curl_easy_getinfo 中。

您已声明

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. 您不会在任何地方打印出大小或速度。

获得它们后,您就不会在main功能结束时打印大小或速度。您需要像以下方式打印它们:

printf("Size: %g KBnSpeed: %g KB/sn", 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

最新更新