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

原文地址:https://www.cnblogs.com/274914765qq/p/4480421.html