zoukankan      html  css  js  c++  java
  • Libcurl

    一、简介

    Libcurl为一个免费开源的,客户端url传输库,支持FTP,FTPS,TFTP,HTTP,HTTPS,GOPHER,TELNET,DICT,FILE和LDAP,跨平台,支持Windows,Unix,Linux等,线程安全,支持Ipv6。并且易于使用。

    二、编译安装

    参考:http://curl.haxx.se/docs/install.html

    依次执行如下命令进行安装

    wget http://curl.haxx.se/download/curl-7.39.0.tar.gz;
    tar -xzvf curl-7.39.0.tar.gz;
    cd curl-7.39.0;
    yum install gcc gcc-c++;
    yum install openssl;
     ./configure --with-ssl;
    make;
    make install;

    三、使用curl-config配置选项

    参考:http://download.csdn.net/detail/u011640816/8665471

    image

    四、常用函数

    1、libcurl的全局初始化及释放

    应该在程序开始时调用初始化函数. 虽然不调用这个初始化函数, libcurl会在curl_easy_init()函数中自动调用. 但在多线程处理时, 可能会出现多次自动调用的情况.

    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)

     

    2、初始化下载handle及释放

    CURL *curl = curl_easy_init();
    
    curl_easy_cleanup(curl);

     

    3、设置下载属性. 及常用参数. 

    CURLcode curl_easy_setopt(CURL *handle, CURLoption option, parameter);

    1)设置下载数据的回调函数

    option:      
         CURLOPT_WRITEFUNCTION //设置回调函数
             回调函数原型为: size_t function( void *ptr, size_t size, size_t nmemb, void *userp);           
            触发:函数将在libcurl接收到数据后被调用。
             参数说明:
                   void *ptr是下载回来的数据.
                   void *userp是用户指针, 用户通过这个指针传输自己的数据.
         
         CURLOPT_WRITEDATA     //设置回调函数中的void *userp指针的来源

    2)控制下载进度

    option:
         CURLOPT_NOPROGRESS  
         说明:为了使CURLOPT_PROGRESSFUNCTION被调用. CURLOPT_NOPROGRESS必须被设置为false.
         
         CURLOPT_PROGRESSFUNCTION
         说明:CURLOPT_PROGRESSFUNCTION 指定的函数正常情况下每秒被libcurl调用一次.
    
         CURLOPT_PROGRESSDATA
         说明:CURLOPT_PROGRESSDATA指定的参数将作为CURLOPT_PROGRESSFUNCTION指定函数的参数. 
        

    3)其它常用属性

    option:
         CURLOPT_URL
         说明:设置访问的URI.
    
         CURLOPT_NOSIGNAL
         说明:屏蔽其它信号.
    
         CURLOPT_HEADER
         说明:取数据时连同HTTP头部一起取回.
    
         CURLOPT_HEADERFUNCTION
         CURLOPT_HEADERDATA
         说明:只取HTTP头部数据, 处理与下载数据回调的处理相同. 
    
         CURLOPT_TIMEOUT
         说明:超时时间.
    
         CURLOPT_CONNECTIONTIMEOUT
         说明:连接等待时间.
    
         CURLOPT_FOLLOWLOCATION
        说明:设置支持302重定向
    
         CURLOPT_RANGE
         说明:断点续传, 指定传输分片, 格式:"0-200"

    4) 开始处理

    CURLcode curl_easy_perform(CURL *handle);

    五、编程实例

    参考:http://curl.haxx.se/libcurl/c/

    程序1:shows how to get a remote web page in only four libcurl function calls.

    /*
     * @file: example.c
     */
    
    #include <stdio.h>
    #include <curl/curl.h>
     
    int main(void)
    {
      CURL *curl;
      CURLcode res;
     
      curl = curl_easy_init();
      if(curl) {
        curl_easy_setopt(curl, CURLOPT_URL, "http://example.com");
        /* example.com is redirected, so we tell libcurl to follow redirection */ 
        curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
     
        /* Perform the request, res will get the return code */ 
        res = curl_easy_perform(curl);
        /* Check for errors */ 
        if(res != CURLE_OK)
          fprintf(stderr, "curl_easy_perform() failed: %s
    ",
                  curl_easy_strerror(res));
     
        /* always cleanup */ 
        curl_easy_cleanup(curl);
      }
      return 0;
    }

    编译

    gcc -o example1 example1.c -lcurl

    运行

    image

    程序2:gets a single HTTPS page

    /*
     *@file:example2.c
     */
    
    
    #include <stdio.h>
    #include <curl/curl.h>
    
    int main(void)
    {
      CURL *curl;
      CURLcode res;
    
      curl_global_init(CURL_GLOBAL_DEFAULT);
    
      curl = curl_easy_init();
      if(curl) {
        curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    
    #ifdef SKIP_PEER_VERIFICATION
        /*
         * If you want to connect to a site who isn't using a certificate that is
         * signed by one of the certs in the CA bundle you have, you can skip the
         * verification of the server's certificate. This makes the connection
         * A LOT LESS SECURE.
         *
         * If you have a CA cert for the server stored someplace else than in the
         * default bundle, then the CURLOPT_CAPATH option might come handy for
         * you.
         */
        curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
    #endif
    
    #ifdef SKIP_HOSTNAME_VERIFICATION
        /*
         * If the site you're connecting to uses a different host name that what
         * they have mentioned in their server certificate's commonName (or
         * subjectAltName) fields, libcurl will refuse to connect. You can skip
         * this check, but this will make the connection less secure.
         */
        curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
    #endif
    
        /* Perform the request, res will get the return code */
        res = curl_easy_perform(curl);
        /* Check for errors */
        if(res != CURLE_OK)
          fprintf(stderr, "curl_easy_perform() failed: %s
    ",
                  curl_easy_strerror(res));
    
        /* always cleanup */
        curl_easy_cleanup(curl);
      }
    
      curl_global_cleanup();
    
      return 0;
    }

    编译

    gcc -o example2 example2.c -lcurl

    运行

    image

    程序3:shows how to get a remote https page and a set of various SSL-controlling options

    /*
     * @file:example3.c
     * @brief: shows how to get a remote https page and a set of various SSL-controlling options
     */
    
    #include <stdio.h>
    
    #include <curl/curl.h>
    
    /* some requirements for this to work:
       1.   set pCertFile to the file with the client certificate
       2.   if the key is passphrase protected, set pPassphrase to the
            passphrase you use
       3.   if you are using a crypto engine:
       3.1. set a #define USE_ENGINE
       3.2. set pEngine to the name of the crypto engine you use
       3.3. set pKeyName to the key identifier you want to use
       4.   if you don't use a crypto engine:
       4.1. set pKeyName to the file name of your client key
       4.2. if the format of the key file is DER, set pKeyType to "DER"
    
       !! verify of the server certificate is not implemented here !!
    
       **** This example only works with libcurl 7.9.3 and later! ****
    
    */
    
    int main(void)
    {
      int i;
      CURL *curl;
      CURLcode res;
      FILE *headerfile;
      const char *pPassphrase = NULL;
    
      static const char *pCertFile = "testcert.pem";
      static const char *pCACertFile="cacert.pem";
    
      const char *pKeyName;
      const char *pKeyType;
    
      const char *pEngine;
    
    #ifdef USE_ENGINE
      pKeyName  = "rsa_test";
      pKeyType  = "ENG";
      pEngine   = "chil";            /* for nChiper HSM... */
    #else
      pKeyName  = "testkey.pem";
      pKeyType  = "PEM";
      pEngine   = NULL;
    #endif
    
      headerfile = fopen("dumpit", "w");
    
      curl_global_init(CURL_GLOBAL_DEFAULT);
    
      curl = curl_easy_init();
      if(curl) {
        /* what call to write: */
        curl_easy_setopt(curl, CURLOPT_URL, "HTTPS://your.favourite.ssl.site");
        curl_easy_setopt(curl, CURLOPT_HEADERDATA, headerfile);
    
        for(i = 0; i < 1; i++) /* single-iteration loop, just to break out from */
        {
          if (pEngine)             /* use crypto engine */
          {
            if (curl_easy_setopt(curl, CURLOPT_SSLENGINE,pEngine) != CURLE_OK)
            {                     /* load the crypto engine */
              fprintf(stderr,"can't set crypto engine
    ");
              break;
            }
            if (curl_easy_setopt(curl, CURLOPT_SSLENGINE_DEFAULT,1L) != CURLE_OK)
            { /* set the crypto engine as default */
              /* only needed for the first time you load
                 a engine in a curl object... */
              fprintf(stderr,"can't set crypto engine as default
    ");
              break;
            }
          }
          /* cert is stored PEM coded in file... */
          /* since PEM is default, we needn't set it for PEM */
          curl_easy_setopt(curl,CURLOPT_SSLCERTTYPE,"PEM");
    
          /* set the cert for client authentication */
          curl_easy_setopt(curl,CURLOPT_SSLCERT,pCertFile);
    
          /* sorry, for engine we must set the passphrase
             (if the key has one...) */
          if (pPassphrase)
            curl_easy_setopt(curl,CURLOPT_KEYPASSWD,pPassphrase);
    
          /* if we use a key stored in a crypto engine,
             we must set the key type to "ENG" */
          curl_easy_setopt(curl,CURLOPT_SSLKEYTYPE,pKeyType);
    
          /* set the private key (file or ID in engine) */
          curl_easy_setopt(curl,CURLOPT_SSLKEY,pKeyName);
    
          /* set the file with the certs vaildating the server */
          curl_easy_setopt(curl,CURLOPT_CAINFO,pCACertFile);
    
          /* disconnect if we can't validate server's cert */
          curl_easy_setopt(curl,CURLOPT_SSL_VERIFYPEER,1L);
    
          /* Perform the request, res will get the return code */
          res = curl_easy_perform(curl);
          /* Check for errors */
          if(res != CURLE_OK)
            fprintf(stderr, "curl_easy_perform() failed: %s
    ",
                    curl_easy_strerror(res));
    
          /* we are done... */
        }
        /* always cleanup */
        curl_easy_cleanup(curl);
      }
    
      curl_global_cleanup();
    
      return 0;
    }

    编译

    gcc -o example3 example3.c -lcurl

    运行

    image

    程序4:get HTTP with headers separate

    /*
     *
     *@file:example4.c
     *@brief:get HTTP with headers separate
     *
     */
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    
    #include <curl/curl.h>
    
    static size_t write_data(void *ptr, size_t size, size_t nmemb, void *stream)
    {
      int written = fwrite(ptr, size, nmemb, (FILE *)stream);
      return written;
    }
    
    int main(void)
    {
      CURL *curl_handle;
      static const char *headerfilename = "head.out";
      FILE *headerfile;
      static const char *bodyfilename = "body.out";
      FILE *bodyfile;
    
      curl_global_init(CURL_GLOBAL_ALL);
    
      /* init the curl session */
      curl_handle = curl_easy_init();
    
      /* set URL to get */
      curl_easy_setopt(curl_handle, CURLOPT_URL, "http://example.com");
    
      /* no progress meter please */
      curl_easy_setopt(curl_handle, CURLOPT_NOPROGRESS, 1L);
    
      /* send all data to this function  */
      curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, write_data);
    
      /* open the header file */
      headerfile = fopen(headerfilename, "wb");
      if(!headerfile) {
        curl_easy_cleanup(curl_handle);
        return -1;
      }
    
      /* open the body file */
      bodyfile = fopen(bodyfilename, "wb");
      if(!bodyfile) {
        curl_easy_cleanup(curl_handle);
        fclose(headerfile);
        return -1;
      }
    
      /* we want the headers be written to this file handle */
      curl_easy_setopt(curl_handle, CURLOPT_HEADERDATA, headerfile);
    
      /* we want the body be written to this file handle instead of stdout */
      curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, bodyfile);
    
      /* get it! */
      curl_easy_perform(curl_handle);
    
      /* close the header file */
      fclose(headerfile);
    
      /* close the body file */
      fclose(bodyfile);
    
      /* cleanup curl stuff */
      curl_easy_cleanup(curl_handle);
    
      return 0;
    }

    编译

    gcc -o example4 example4.c -lcurl

    运行

    image

    程序5:makes PUTs a local file to a HTTP server

    /*
     *
     *@file:example5.c
     *@brief:makes PUTs a local file to a HTTP server
     *
     */
    
    #include <stdio.h>
    #include <fcntl.h>
    #include <sys/stat.h>
    #include <curl/curl.h>
    
    /*
     * This example shows a HTTP PUT operation. PUTs a file given as a command
     * line argument to the URL also given on the command line.
     *
     * This example also uses its own read callback.
     *
     * Here's an article on how to setup a PUT handler for Apache:
     * http://www.apacheweek.com/features/put
     */
    
    static size_t read_callback(void *ptr, size_t size, size_t nmemb, void *stream)
    {
      size_t retcode;
      curl_off_t nread;
    
      /* in real-world cases, this would probably get this data differently
         as this fread() stuff is exactly what the library already would do
         by default internally */
      retcode = fread(ptr, size, nmemb, stream);
    
      nread = (curl_off_t)retcode;
    
      fprintf(stderr, "*** We read %" CURL_FORMAT_CURL_OFF_T
              " bytes from file
    ", nread);
    
      return retcode;
    }
    
    int main(int argc, char **argv)
    {
      CURL *curl;
      CURLcode res;
      FILE * hd_src ;
      struct stat file_info;
    
      char *file;
      char *url;
    
      if(argc < 3)
        return 1;
    
      file= argv[1];
      url = argv[2];
    
      /* get the file size of the local file */
      stat(file, &file_info);
    
      /* get a FILE * of the same file, could also be made with
         fdopen() from the previous descriptor, but hey this is just
         an example! */
      hd_src = fopen(file, "rb");
    
      /* In windows, this will init the winsock stuff */
      curl_global_init(CURL_GLOBAL_ALL);
    
      /* get a curl handle */
      curl = curl_easy_init();
      if(curl) {
        /* we want to use our own read function */
        curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_callback);
    
        /* enable uploading */
        curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
    
        /* HTTP PUT please */
        curl_easy_setopt(curl, CURLOPT_PUT, 1L);
    
        /* specify target URL, and note that this URL should include a file
           name, not only a directory */
        curl_easy_setopt(curl, CURLOPT_URL, url);
    
        /* now specify which file to upload */
        curl_easy_setopt(curl, CURLOPT_READDATA, hd_src);
    
        /* provide the size of the upload, we specicially typecast the value
           to curl_off_t since we must be sure to use the correct data size */
        curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE,
                         (curl_off_t)file_info.st_size);
    
        /* Now run off and do what you've been told! */
        res = curl_easy_perform(curl);
        /* Check for errors */
        if(res != CURLE_OK)
          fprintf(stderr, "curl_easy_perform() failed: %s
    ",
                  curl_easy_strerror(res));
    
        /* always cleanup */
        curl_easy_cleanup(curl);
      }
      fclose(hd_src); /* close the local file */
    
      curl_global_cleanup();
      return 0;
    }

    编译

    gcc -o example5 example5.c -lcurl

    运行

    image

    程序6:shows how to build a RFC1867-style form post and send it to a HTTP server.

    /*
     *
     *@file:example6.c
     *@brief:shows how to build a RFC1867-style form post and send it to a HTTP server.
     *
     */
    
    
    /* Example code that uploads a file name 'foo' to a remote script that accepts
     * "HTML form based" (as described in RFC1738) uploads using HTTP POST.
     *
     * The imaginary form we'll fill in looks like:
     *
     * <form method="post" enctype="multipart/form-data" action="examplepost.cgi">
     * Enter file: <input type="file" name="sendfile" size="40">
     * Enter file name: <input type="text" name="filename" size="30">
     * <input type="submit" value="send" name="submit">
     * </form>
     *
     * This exact source code has not been verified to work.
     */
    
    #include <stdio.h>
    #include <string.h>
    
    #include <curl/curl.h>
    
    int main(int argc, char *argv[])
    {
      CURL *curl;
      CURLcode res;
    
      struct curl_httppost *formpost=NULL;
      struct curl_httppost *lastptr=NULL;
      struct curl_slist *headerlist=NULL;
      static const char buf[] = "Expect:";
    
      curl_global_init(CURL_GLOBAL_ALL);
    
      /* Fill in the file upload field */
      curl_formadd(&formpost,
                   &lastptr,
                   CURLFORM_COPYNAME, "sendfile",
                   CURLFORM_FILE, "postit2.c",
                   CURLFORM_END);
    
      /* Fill in the filename field */
      curl_formadd(&formpost,
                   &lastptr,
                   CURLFORM_COPYNAME, "filename",
                   CURLFORM_COPYCONTENTS, "postit2.c",
                   CURLFORM_END);
    
    
      /* Fill in the submit field too, even if this is rarely needed */
      curl_formadd(&formpost,
                   &lastptr,
                   CURLFORM_COPYNAME, "submit",
                   CURLFORM_COPYCONTENTS, "send",
                   CURLFORM_END);
    
      curl = curl_easy_init();
      /* initalize custom header list (stating that Expect: 100-continue is not
         wanted */
      headerlist = curl_slist_append(headerlist, buf);
      if(curl) {
        /* what URL that receives this POST */
        curl_easy_setopt(curl, CURLOPT_URL, "http://example.com/examplepost.cgi");
        if ( (argc == 2) && (!strcmp(argv[1], "noexpectheader")) )
          /* only disable 100-continue header if explicitly requested */
          curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist);
        curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost);
    
        /* Perform the request, res will get the return code */
        res = curl_easy_perform(curl);
        /* Check for errors */
        if(res != CURLE_OK)
          fprintf(stderr, "curl_easy_perform() failed: %s
    ",
                  curl_easy_strerror(res));
    
        /* always cleanup */
        curl_easy_cleanup(curl);
    
        /* then cleanup the formpost chain */
        curl_formfree(formpost);
        /* free slist */
        curl_slist_free_all (headerlist);
      }
      return 0;
    }

    编译

    gcc -o example6 example6.c -lcurl

    运行

    image

    程序7:shows how you can use the debug callback to get a full trace of all protocol data being sent/received (and more)

    /*
     *
     *@file:example7.c
     *@brief:shows how to build a RFC1867-style form post and send it to a HTTP server.
     *
     */
    
    #include <stdio.h>
    #include <curl/curl.h>
    
    struct data {
        char trace_ascii; /* 1 or 0 */
    };
    
    static void dump(const char *text, FILE *stream, unsigned char *ptr, size_t size, char nohex)
    {
        size_t i;
        size_t c;
    
        unsigned int width=0x10;
    
        if(nohex)
            /* without the hex output, we can fit more on screen */
            width = 0x40;
    
        fprintf(stream, "%s, %10.10ld bytes (0x%8.8lx)
    ",
                text, (long)size, (long)size);
    
        for(i=0; i<size; i+= width) {
    
            fprintf(stream, "%4.4lx: ", (long)i);
    
            if(!nohex) {
                /* hex not disabled, show it */
                for(c = 0; c < width; c++)
                    if(i+c < size)
                        fprintf(stream, "%02x ", ptr[i+c]);
                    else
                        fputs("   ", stream);
            }
    
            for(c = 0; (c < width) && (i+c < size); c++) {
                /* check for 0D0A; if found, skip past and start a new line of output */
                if (nohex && (i+c+1 < size) && ptr[i+c]==0x0D && ptr[i+c+1]==0x0A) {
                    i+=(c+2-width);
                    break;
                }
                fprintf(stream, "%c",
                        (ptr[i+c]>=0x20) && (ptr[i+c]<0x80)?ptr[i+c]:'.');
                /* check again for 0D0A, to avoid an extra 
     if it's at width */
                if (nohex && (i+c+2 < size) && ptr[i+c+1]==0x0D && ptr[i+c+2]==0x0A) {
                    i+=(c+3-width);
                    break;
                }
            }
            fputc('
    ', stream); /* newline */
        }
        fflush(stream);
    }
    
    static int my_trace(CURL *handle, curl_infotype type, char *data, size_t size, void *userp)
    {
        struct data *config = (struct data *)userp;
        const char *text;
        (void)handle; /* prevent compiler warning */
    
        switch (type) {
            case CURLINFO_TEXT:
                fprintf(stderr, "== Info: %s", data);
            default: /* in case a new one is introduced to shock us */
                return 0;
    
            case CURLINFO_HEADER_OUT:
                text = "=> Send header";
                break;
            case CURLINFO_DATA_OUT:
                text = "=> Send data";
                break;
            case CURLINFO_SSL_DATA_OUT:
                text = "=> Send SSL data";
                break;
            case CURLINFO_HEADER_IN:
                text = "<= Recv header";
                break;
            case CURLINFO_DATA_IN:
                text = "<= Recv data";
                break;
            case CURLINFO_SSL_DATA_IN:
                text = "<= Recv SSL data";
                break;
        }
    
        dump(text, stderr, (unsigned char *)data, size, config->trace_ascii);
        return 0;
    }
    
    int main(void)
    {
        CURL *curl;
        CURLcode res;
        struct data config;
    
        config.trace_ascii = 1; /* enable ascii tracing */
    
        curl = curl_easy_init();
        if(curl) {
            curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, my_trace);
            curl_easy_setopt(curl, CURLOPT_DEBUGDATA, &config);
    
            /* the DEBUGFUNCTION has no effect until we enable VERBOSE */
            curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
    
            /* example.com is redirected, so we tell libcurl to follow redirection */
            curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
    
            curl_easy_setopt(curl, CURLOPT_URL, "http://example.com/");
            res = curl_easy_perform(curl);
            /* Check for errors */
            if(res != CURLE_OK)
                fprintf(stderr, "curl_easy_perform() failed: %s
    ",
                        curl_easy_strerror(res));
    
            /* always cleanup */
            curl_easy_cleanup(curl);
        }
        return 0;
    }

    编译

    gcc -o example7 example7.c -lcurl

    运行:

    image

  • 相关阅读:
    转:同步、异步、阻塞和非阻塞
    转:回调函数
    转:同步/异步与阻塞/非阻塞的区别
    转:Socket在阻塞模式下的信息收发和文件接收
    转:直接用socket实现HTTP协议
    链接错误 LINK : fatal error LNK1104: 无法打开文件“XX.obj”
    转:MFC中常用类,宏,函数介绍
    转:线程同步技术剖析
    转:线程同步
    转:C++回调函数用法
  • 原文地址:https://www.cnblogs.com/274914765qq/p/4480421.html
Copyright © 2011-2022 走看看