Linux与windows下C语言使用curl库的安装使用以及访问HTTP下载文件

举报
DS小龙哥 发表于 2024/02/28 13:16:14 2024/02/28
【摘要】 cURL 是一个命令行工具和库,用于传输数据,支持多种协议,如 HTTP、HTTPS、FTP 等。可以在终端中用来发送和接收数据,执行各种网络操作,如下载文件、上传文件、发送 POST 请求等。

一、前言

cURL 是一个命令行工具和库,用于传输数据,支持多种协议,如 HTTP、HTTPS、FTP 等。可以在终端中用来发送和接收数据,执行各种网络操作,如下载文件、上传文件、发送 POST 请求等。


以下是一些常用的 cURL 命令选项:

(1)发送 GET 请求:

curl [URL]

(2)发送 POST 请求:

curl -X POST [URL] --data "key1=value1&key2=value2"

(3)下载文件:

curl -O [URL]

(4)显示响应头信息:

curl -i [URL]

(5)设置请求头信息:

curl -H "Content-Type: application/json" [URL]

(6)设置超时时间:

curl --connect-timeout 10 [URL]

(7)跟踪重定向:

curl -L [URL]

(8)使用代理服务器:

curl -x proxy_host:port [URL]

(9)保存输出到文件:

curl -o output.txt [URL]

cURL 提供了丰富的选项和功能,可以用于测试 API、进行网络调试、批量下载文件等各种场景。通过结合不同的选项,可以实现许多复杂的网络操作。如果在命令行中使用 cURL,可以查看 cURL 的文档以了解多详细信息和选项用法。


二、Linux下curl下载

要在 Linux 系统下编译和安装 cURL 源码,可以按照以下步骤进行操作:

(1)下载 cURL 源码: 首先,在 cURL 官方网站(https://curl.se/download.html)上下载最新版本的 cURL 源码压缩包,并解压到本地目录。

(2)进入源码目录: 使用终端进入解压后的 cURL 源码目录,例如:

cd curl-7.x.x  # 进入解压后的 cURL 源码目录

(3)配置编译参数: 运行以下命令配置 cURL 的编译参数:

./configure

可以通过 ./configure --help 查看可用的配置选项。

(4)编译源码: 运行以下命令编译 cURL 源码:

make

这将编译 cURL 并生成可执行文件。

(5)安装 cURL: 运行以下命令安装编译后的 cURL 文件到系统中:

sudo make install

这将把 cURL 的可执行文件、库文件和头文件安装到系统路径中。

(6)验证安装: 运行以下命令验证 cURL 是否成功安装:

curl --version

如果成功安装,会显示 cURL 的版本信息。

通过以上步骤,就可以在 Linux 系统下编译和安装 cURL 源码。

在执行 make install 命令时,Ubuntu下需要使用管理员权限(sudo),以便将文件安装到系统目录。


下面是 使用 libcurl 库来下载文件:

#include <stdio.h>
#include <curl/curl.h>
​
int main(void)
{
    CURL *curl;
    FILE *fp;
    CURLcode res;
​
    const char *url = "https://www.example.com/file-to-download.txt";
    const char *output_filename = "downloaded_file.txt";
​
    curl = curl_easy_init();
    if (curl) {
        fp = fopen(output_filename, "wb");
        curl_easy_setopt(curl, CURLOPT_URL, url);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
​
        res = curl_easy_perform(curl);
        if (res != CURLE_OK) {
            fprintf(stderr, "Failed to download: %s\n", curl_easy_strerror(res));
        }
​
        curl_easy_cleanup(curl);
        fclose(fp);
    } else {
        fprintf(stderr, "Failed to initialize libcurl\n");
    }
​
    return 0;
}

在这个示例代码中,包含了必要的头文件 <stdio.h><curl/curl.h>,定义了要下载的文件 URL 和保存到本地的文件名。创建了一个 libcurl 的句柄 CURL *curl,打开了一个文件指针 FILE *fp 用于保存下载的文件。

初始化 libcurl 并设置下载的 URL 和保存文件的操作,执行下载操作并将结果写入到文件中。

最后清理资源并关闭文件指针。

可以将以上代码保存到一个 .c 文件中,然后使用以下方式编译和运行:

gcc -o download_program download_program.c -lcurl
./download_program




三、Windows下curl下载

curl for windows : https://curl.se/windows/

下载页面如图:

image-20220513134431494

image-20220513134501163

解压后的可执行文件位置:

image-20220513134530563

下面是解压后的文件目录:

image-20220513134631915

在命令行使用curl测试下载文件:

image-20220513134729784

四、通过命令行使用curl

curl可以直接调用函数库完成功能设计、也可以直接调用可执行文件完成需要的功能,下面这里就介绍,在windows下,通过CreateProcess调用curl命令函数完成文件下载。使用curl实现HTTP协议文件下载成功,通过给定的连接地址,可以完成文件下载,百分比进度返回等等。

 /**************************************************
 作者: DS小龙哥
 功能: 执行命令
 参数解释:
 CallBackFunction_p func_p  :回调函数,用于通知进度执行过程
 char *text  //进度的转码过程,详细描述.描述当前这个操作是做什么.
 char *total_time   //执行的总时间
 char *cmd //执行的命令
 **************************************************/
 int file_down_func(CallBackFunction_p func_p, const char *text, const char *total_time, const  char *cmd)
 {
         BOOL run_pipe;
 
         PROCESS_INFORMATION pi;
         STARTUPINFO si;
         BOOL ret = FALSE;
         DWORD flags = CREATE_NO_WINDOW;
 
 
         char pBuffer[210];
         SECURITY_ATTRIBUTES sa;
         sa.nLength = sizeof(SECURITY_ATTRIBUTES);
         sa.lpSecurityDescriptor = NULL;
         sa.bInheritHandle = TRUE;
         HANDLE hReadPipe, hWritePipe;
         run_pipe = CreatePipe(&hReadPipe, &hWritePipe, &sa, 0);
 
         if (run_pipe != 1)
         {
             printf("创建匿名管道文件失败=%d\n", run_pipe);
             return -1;
         }
 
         ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
         ZeroMemory(&si, sizeof(STARTUPINFO));
         si.cb = sizeof(STARTUPINFO);
         si.dwFlags |= STARTF_USESTDHANDLES;
         si.hStdInput = NULL;
         si.hStdError = hWritePipe;
         si.hStdOutput = hWritePipe;
 
         wchar_t cmd_wchar[1024];
         CharToWchar(cmd, cmd_wchar);
 
         //TCHAR cmd[] = TEXT("ffmpeg -i D:\123.mp4 -vf reverse D:\out\out1.mp4");
 
         ret = CreateProcess(NULL, cmd_wchar, NULL, NULL, TRUE, flags, NULL, NULL, &si, &pi);
 
         if (ret)
         {
             while (true)
             {
                 DWORD ExitCode = 0;
                 //判断进程是否执行结束
                 printf("正在执行...GetExitCodeProcess\r\n");
                 GetExitCodeProcess(pi.hProcess, &ExitCode);
                 printf("ExitCode:%d\r\n", ExitCode);
                 if (ExitCode == STILL_ACTIVE) //正在运行
                 {
                     DWORD RSize = 0;
                     BOOL run_s = 0;
                     printf("正在执行...ReadFile\r\n");
                     run_s = ReadFile(hReadPipe, pBuffer, sizeof(pBuffer), &RSize, NULL);
                     pBuffer[RSize - 1] = '\0';
 
                     printf("执行过程:%s,%d,%d,%s\n", version_str, run_s, RSize, pBuffer);
 
                     char number_buff[10]="\0"; //存放百分比
 
                     printf("pBuffer=%s\r\n", pBuffer);
                     //通过回调函数向外部返回进度提示
                     for (size_t i = 0; i < 10 && pBuffer[i]!='\0'; i++)
                     {
                         if (pBuffer[i] >= '0' && pBuffer[i] <= '9')
                         {
                             //得到百分比值
                             for (size_t j = 0; j < 9 && pBuffer[i+j] != '\0'; j++)
                             {
                                 //printf("@@%c@@\r\n", pBuffer[i + j]);
                                 if (pBuffer[i+j] >= '0' && pBuffer[i+j] <= '9')
                                 {
                                     number_buff[j] = pBuffer[i + j];
                                 }
                                 else
                                 {
                                     number_buff[j] = '\0';
                                     break;
                                 }
                             }
                             break;
                         }
                     }
 
                     //  0  926M    0 6463k    0     0  7378k      0  0:02:08 --:--:--  0:02:08 7386
                     //如果找到进度的位置
                     if (strlen(number_buff)>0)
                     {
                         std::string  out_str;
 
                         out_str = text;
                         out_str += ",";
                         out_str += "100";
                         out_str += ",";
                         out_str += number_buff;
 
                         printf("回调:%s\r\n", out_str.c_str());
                         //将执行的结果再回调出去
                         if (func_p)
                         {
                             func_p(out_str.c_str());
                         }
                     }
                 }
                 else //结束
                 {
                     printf("执行完毕,ExitCode=%d\r\n", ExitCode);
                     break;
                 }
             }
 
             printf("正在等待子进程结束....\n");
             //等待结束
             WaitForSingleObject(pi.hProcess, INFINITE);
 
             CloseHandle(pi.hProcess);
             CloseHandle(pi.hThread);
             printf("子进程执行完毕....\n");
             return 0;
         }
         printf("子进程创建失败:%d\n", ret);
     return -1;
 }
 
 
 
 int main()
 {
         string VideoCacheFilePath = "D:\out";
 
     //下载的文件名称
     string file_path = "http://192.168.1.110:8001/Uploads/1/哈哈哈.MP4";
 
     //如果返回为真就表示是网络地址
     if (strstr(file_path.c_str(), "http:") ||
         strstr(file_path.c_str(), "https:"))
     {
         //1.获取不带路径的文件名
         string::size_type iPos;
         if (strstr(file_path.c_str(), "\"))
         {
             iPos = file_path.find_last_of('\') + 1;
         }
         else
         {
             iPos = file_path.find_last_of('/') + 1;
         }
 
         //得到文件名称
         string base_file = file_path.substr(iPos, file_path.length() - iPos);
 
         //得到完整的文件下载存储路径
         string VideoPath_tmp = VideoCacheFilePath;
         VideoPath_tmp += "\";
         VideoPath_tmp += base_file;
 
         //判断文件是否存在
         printf("文件存储路径:%s\r\n", VideoPath_tmp.c_str());
         FILE *file_p = fopen(VideoPath_tmp.c_str(),"rb");
         //不存在就下载
         if (file_p == nullptr)
         {
             //切换目录,进入到curl命令所在的目录
             _chdir(VideoCacheFilePath.c_str());
 
             string cmd = "curl -O ";
             cmd += file_path;
             //启动下载文件
             file_down_func(NULL, base_file.c_str(),"100",cmd.c_str());
         }
         else
         {
             printf("文件存在不需要下载.\r\n");
             fclose(file_p);
         }
     }
     return 0;
 }
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。