利用libcurl库进行http通讯网络

本文章使用的是Ubuntu18.04来完成程序编译运行。

一、了解libcurl

  1. libcurl是什么
    libcurl是一个跨平台的网络协议库,支持http, https, ftp, gopher, telnet, dict, file, ldap 协议等。
    libcurl同样支持HTTPS证书授权,HTTP POST, HTTP PUT, FTP 上传, HTTP基本表单上传,代理,cookies,用户认证等。

  2. libcurl基本函数
    ①CURLcode curl_global_init(long flags)
    这个函数只能用一次。

    参数:flags
    CURL_GLOBAL_ALL //初始化所有的可能的调用。
    CURL_GLOBAL_SSL //初始化支持 安全套接字层。
    CURL_GLOBAL_WIN32 //初始化win32套接字库。
    CURL_GLOBAL_NOTHING //没有额外的初始化。

    ②void curl_global_cleanup(void)
    在结束libcurl使用的时候,用来对curl_global_init做的工作清理。类似于clean。
    ③char *curl_version( )
    打印当前libcurl库的版本。
    ④CURL *curl_easy_init( )
    用来初始化一个CURL的指针, 相应的在调用结束时要用curl_easy_cleanup函数清理。
    ⑤void curl_easy_cleanup(CURL *handle);
    用来结束一个会话。

    参数:
    CURL类型的指针。

    ⑥CURLcode curl_easy_setopt(CURL *handle, CURLoption option, parameter);
    用于告诉curl库程序将有如何的行为。

    参数:
    CURL类型的指针。
    各种CURLoption类型的选项。
    parameter 这个参数 既可以是个函数的指针,也可以是某个对象的指针,也可以是个long型的变量.它用什么这取决于第二个参数。
    CURLoption 这个参数的取值很多。

  3. 利用libcurl完成传输任务的流程
    ①调用curl_global_init()初始化libcurl
    ②调用curl_easy_init()函数得到 easy interface型指针
    ③调用curl_easy_setopt()设置传输选项
    ④根据curl_easy_setopt()设置的传输选项,实现回调函数以完成用户特定任务
    ⑤调用curl_easy_perform()函数完成传输任务
    ⑥调用curl_easy_cleanup()释放内存

    注意:curl_easy_setopt()极其重要。

二、通过实例认识libcurl

  1. 基本的http GET/POST操作
    代码

    #include <stdio.h>
    #include <curl/curl.h>
    bool getUrl(char *filename)
    {
          
          
        CURL *curl;
        CURLcode res;
        FILE *fp;
        if ((fp = fopen(filename, "w")) == NULL)  // 返回结果用文件存储
            return false;
        struct curl_slist *headers = NULL;
        headers = curl_slist_append(headers, "Accept: Agent-007");
        curl = curl_easy_init();    // 初始化
        if (curl)
        {
          
          
            //curl_easy_setopt(curl, CURLOPT_PROXY, "10.99.60.201:8080");// 代理
            curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);// 改协议头
            curl_easy_setopt(curl, CURLOPT_URL,"http://www.baidu.com");
            curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp); //将返回的http头输出到fp指向的文件
            curl_easy_setopt(curl, CURLOPT_HEADERDATA, fp); //将返回的html主体数据输出到fp指向的文件
            res = curl_easy_perform(curl);   // 执行
            if (res != 0) {
          
          
    
                curl_slist_free_all(headers);
                curl_easy_cleanup(curl);
            }
            fclose(fp);
            return true;
        }
    }
    bool postUrl(char *filename)
    {
          
          
        CURL *curl;
        CURLcode res;
        FILE *fp;
        if ((fp = fopen(filename, "w")) == NULL)
            return false;
        curl = curl_easy_init();
        if (curl)
        {
          
          
            curl_easy_setopt(curl, CURLOPT_COOKIEFILE, "/tmp/cookie.txt"); // 指定cookie文件
            curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "&logintype=uid&u=xieyan&psw=xxx86");    // 指定post内容
            //curl_easy_setopt(curl, CURLOPT_PROXY, "10.99.60.201:8080");
            curl_easy_setopt(curl, CURLOPT_URL, " http://mail.sina.com.cn/cgi-bin/login.cgi ");   // 指定url
            curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
            res = curl_easy_perform(curl);
            curl_easy_cleanup(curl);
        }
        fclose(fp);
        return true;
    }
    int main(void)
    {
          
          
        getUrl("/tmp/get.html");
        postUrl("/tmp/post.html");
    }
    

    编译

    gcc get_post.c -o get_post –curl

    在这里插入图片描述
    解决方式

    gcc get_post.c -o get_post

    在这里插入图片描述
    将代码中的bool修改成int,false修改为0,true修改为1。
    在这里插入图片描述
    将编译语句修改

    gcc get_post.c -o get_post –curl

    运行

    ./get_post

    运行后get.html文件内容如下在这里插入图片描述
    post.html文件内容为空。

  2. 获取html网页
    代码

    #include <stdio.h>
    #include <curl/curl.h>
    #include <stdlib.h>
    int main(int argc, char *argv[])
    {
          
          
        CURL *curl;             //定义CURL类型的指针
    CURLcode res;           //定义CURLcode类型的变量,保存返回状态码
        if(argc!=2)
        {
          
          
            printf("Usage : file <url>;\n");
            exit(1);
        }
     
        curl = curl_easy_init();        //初始化一个CURL类型的指针
        if(curl!=NULL)
        {
          
          
            //设置curl选项. 其中CURLOPT_URL是让用户指 定url. argv[1]中存放的命令行传进来的网址
            curl_easy_setopt(curl, CURLOPT_URL, argv[1]);        
            //调用curl_easy_perform 执行我们的设置.并进行相关的操作. 在这 里只在屏幕上显示出来.
            res = curl_easy_perform(curl);
            //清除curl操作.
            curl_easy_cleanup(curl);
        }
        return 0;
    }
    

    编译

    gcc get_html.c -o get_html -lcurl

    运行

    ./get_html http://www.baidu.com

    在这里插入图片描述

  3. 网页下载保存
    代码

    // 采用CURLOPT_WRITEFUNCTION 实现网页下载保存功能
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
     
    #include <curl/curl.h>
    //#include <curl/types.h>
    #include <curl/easy.h>
     
    FILE *fp;  //定义FILE类型指针
    //这个函数是为了符合CURLOPT_WRITEFUNCTION而构造的
    //完成数据保存功能
    size_t write_data(void *ptr, size_t size, size_t nmemb, void *stream)  
    {
          
          
        int written = fwrite(ptr, size, nmemb, (FILE *)fp);
        return written;
    }
     
    int main(int argc, char *argv[])
    {
          
          
        CURL *curl;
     
        curl_global_init(CURL_GLOBAL_ALL);  
        curl=curl_easy_init();
        curl_easy_setopt(curl, CURLOPT_URL, argv[1]);  
     
        if((fp=fopen(argv[2],"w"))==NULL)
        {
          
          
            curl_easy_cleanup(curl);
            exit(1);
        }
    //CURLOPT_WRITEFUNCTION 将后继的动作交给write_data函数处理
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);  
        curl_easy_perform(curl);
        curl_easy_cleanup(curl);
        exit(0);
    }
    

    编译

    gcc save_html.c -o save_html -lcurl

    运行

    ./save_html http://www.baidu.com ./baidu
    将百度的网页html保存到当前文件夹的baidu文件中。

    在这里插入图片描述

  4. 断点续传
    代码

    //采用CURLOPT_RESUME_FROM_LARGE 实现文件断点续传功能
    #include <stdlib.h>
    #include <stdio.h>
    #include <sys/stat.h>
     
    #include <curl/curl.h>
    //这个函数为CURLOPT_HEADERFUNCTION参数构造
    /* 从http头部获取文件size*/
    size_t getcontentlengthfunc(void *ptr, size_t size, size_t nmemb, void *stream) {
          
          
           int r;
           long len = 0;
     
           /* _snscanf() is Win32 specific */
           // r = _snscanf(ptr, size * nmemb, "Content-Length: %ld\n", &len);
     r = sscanf(ptr, "Content-Length: %ld\n", &len);
           if (r) /* Microsoft: we don't read the specs */
                  *((long *) stream) = len;
     
           return size * nmemb;
    }
     
    /* 保存下载文件 */
    size_t wirtefunc(void *ptr, size_t size, size_t nmemb, void *stream)
    {
          
          
            return fwrite(ptr, size, nmemb, stream);
    }
     
    /*读取上传文件 */
    size_t readfunc(void *ptr, size_t size, size_t nmemb, void *stream)
    {
          
          
           FILE *f = stream;
           size_t n;
     
           if (ferror(f))
                  return CURL_READFUNC_ABORT;
     
           n = fread(ptr, size, nmemb, f) * size;
     
           return n;
    }
     
    // 下载 或者上传文件函数
    int download(CURL *curlhandle, const char * remotepath, const char * localpath,
               long timeout, long tries)
    {
          
          
           FILE *f;
           curl_off_t local_file_len = -1 ;
           long filesize =0 ;
           
           CURLcode r = CURLE_GOT_NOTHING;
           int c;
      struct stat file_info;
      int use_resume = 0;
      /* 得到本地文件大小 */
      //if(access(localpath,F_OK) ==0)
      
        if(stat(localpath, &file_info) == 0) 
         {
          
          
            local_file_len =  file_info.st_size;
            use_resume  = 1;
          }
      //采用追加方式打开文件,便于实现文件断点续传工作
           f = fopen(localpath, "ab+"); 
           if (f == NULL) {
          
          
                  perror(NULL);
                  return 0;
           }
     
           //curl_easy_setopt(curlhandle, CURLOPT_UPLOAD, 1L);
     
           curl_easy_setopt(curlhandle, CURLOPT_URL, remotepath);
     
                  curl_easy_setopt(curlhandle, CURLOPT_CONNECTTIMEOUT, timeout);  // 设置连接超时,单位秒
           //设置http 头部处理函数
           curl_easy_setopt(curlhandle, CURLOPT_HEADERFUNCTION, getcontentlengthfunc);
           curl_easy_setopt(curlhandle, CURLOPT_HEADERDATA, &filesize);
     // 设置文件续传的位置给libcurl
           curl_easy_setopt(curlhandle, CURLOPT_RESUME_FROM_LARGE, use_resume?local_file_len:0);
     
           curl_easy_setopt(curlhandle, CURLOPT_WRITEDATA, f);
           curl_easy_setopt(curlhandle, CURLOPT_WRITEFUNCTION, wirtefunc);
     
           //curl_easy_setopt(curlhandle, CURLOPT_READFUNCTION, readfunc);
           //curl_easy_setopt(curlhandle, CURLOPT_READDATA, f);
           curl_easy_setopt(curlhandle, CURLOPT_NOPROGRESS, 1L);
           curl_easy_setopt(curlhandle, CURLOPT_VERBOSE, 1L);
      
      
      r = curl_easy_perform(curlhandle);
           
     
           fclose(f);
     
           if (r == CURLE_OK)
                  return 1;
           else {
          
          
                  fprintf(stderr, "%s\n", curl_easy_strerror(r));
                  return 0;
           }
    }
     
    int main(int c, char **argv) {
          
          
           CURL *curlhandle = NULL;
     
           curl_global_init(CURL_GLOBAL_ALL);
           curlhandle = curl_easy_init();
     
           //download(curlhandle, "ftp://user:pass@host/path/file", "C:\\file", 0, 3);
      download(curlhandle , "https://sunlight-dazzling.github.io/file/introduce.txt","./index.asp",1,3);
           curl_easy_cleanup(curlhandle);
           curl_global_cleanup();
     
           return 0;
    }
    

    编译

    gcc resume.c -o resume -lcurl

    运行

    ./resume

    在这里插入图片描述
    在当前目录下可以看到对应下载的文件。

三、总结

通过几个实际例子,可以清楚看出libcurl在获取http网址的网页信息上,是比较方便的。其中,几个实例中,比较难理解应该是断点续传。断点续传指的是将下载或上传任务(一个文件或一个压缩包)人为的划分为几个部分,每一个部分采用一个线程进行上传或下载,当碰到网络故障,可以从已经上传或下载的部分开始继续上传下载未完成的部分,而没有必要从头开始上传下载。这样的方式可以帮助用户节省时间,提高下载或上传的速度。要想更加深入了解libcurl,还需要看更多的资料,才能够正在理解libcurl。

四、参考资料

C++ 用libcurl库进行http通讯网络编程

猜你喜欢

转载自blog.csdn.net/qq_43279579/article/details/110674541