一、簡介
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
四、常用函數
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\n", curl_easy_strerror(res)); /* always cleanup */ curl_easy_cleanup(curl); } return 0; }
編譯
gcc -o example1 example1.c -lcurl
運行
程序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\n", curl_easy_strerror(res)); /* always cleanup */ curl_easy_cleanup(curl); } curl_global_cleanup(); return 0; }
編譯
gcc -o example2 example2.c -lcurl
運行
程序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\n"); 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\n"); 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\n", curl_easy_strerror(res)); /* we are done... */ } /* always cleanup */ curl_easy_cleanup(curl); } curl_global_cleanup(); return 0; }
編譯
gcc -o example3 example3.c -lcurl
運行
程序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
運行
程序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\n", 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\n", 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
運行
程序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\n", 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
運行
程序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)\n", 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 \n 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('\n', 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\n", curl_easy_strerror(res)); /* always cleanup */ curl_easy_cleanup(curl); } return 0; }
編譯
gcc -o example7 example7.c -lcurl
運行: