一、LibCurl基本編程框架
libcurl
個跨平臺的網(wǎng)絡(luò)協(xié)議庫,支持http, https, ftp, gopher, telnet, dict, file, 和ldap 協(xié)議。libcurl同樣支持HTTPS證書授權(quán),HTTP POST, HTTP PUT, FTP 上傳, HTTP基本表單上傳,代理,cookies,和用戶認(rèn)證。想要知道更多關(guān)于libcurl的介紹,可以到官網(wǎng) http://curl.haxx.se/上去了解,在這里不再詳述。
在基于LibCurl的程序里,主要采用callback function (回調(diào)函數(shù))的形式完成傳輸任務(wù),用戶在啟動傳輸前設(shè)置好各類參數(shù)和回調(diào)函數(shù),當(dāng)滿足條件時libcurl將調(diào)用用戶的回調(diào)函數(shù)實現(xiàn)特定功能。下面是利用libcurl完成傳輸任務(wù)的流程:
1.       調(diào)用curl_global_init()初始化libcurl
2.       調(diào)用curl_easy_init()函數(shù)得到 easy interface型指針
3.       調(diào)用curl_easy_setopt()設(shè)置傳輸選項
4.       根據(jù)curl_easy_setopt()設(shè)置的傳輸選項,實現(xiàn)回調(diào)函數(shù)以完成用戶特定任務(wù)
5.       調(diào)用curl_easy_perform()函數(shù)完成傳輸任務(wù)
6.       調(diào)用curl_easy_cleanup()釋放內(nèi)存
在整過過程中設(shè)置curl_easy_setopt()參數(shù)是最關(guān)鍵的,幾乎所有的libcurl程序都要使用它。

二、一些基本的函數(shù)
1.CURLcode curl_global_init(long flags);
描述:
這個函數(shù)只能用一次。(其實在調(diào)用curl_global_cleanup 函數(shù)后仍然可再用)
如果這個函數(shù)在curl_easy_init函數(shù)調(diào)用時還沒調(diào)用,它講由libcurl庫自動調(diào)用,所以多線程下最好主動調(diào)用該函數(shù)以防止在線程中curl_easy_init時多次調(diào)用。
注意:雖然libcurl是線程安全的,但curl_global_init是不能保證線程安全的,所以不要在每個線程中都調(diào)用curl_global_init,應(yīng)該將該函數(shù)的調(diào)用放在主線程中。
參數(shù):flags
CURL_GLOBAL_ALL                      //初始化所有的可能的調(diào)用。
CURL_GLOBAL_SSL                      //初始化支持 安全套接字層。
CURL_GLOBAL_WIN32            //初始化win32套接字庫。
CURL_GLOBAL_NOTHING         //沒有額外的初始化。

2 void curl_global_cleanup(void);
描述:在結(jié)束libcurl使用的時候,用來對curl_global_init做的工作清理。類似于close的函數(shù)。
注意:雖然libcurl是線程安全的,但curl_global_cleanup是不能保證線程安全的,所以不要在每個線程中都調(diào)用curl_global_init,應(yīng)該將該函數(shù)的調(diào)用放在主線程中。

3 char *curl_version( );
描述: 打印當(dāng)前l(fā)ibcurl庫的版本。

4 CURL *curl_easy_init( );
描述:
curl_easy_init用來初始化一個CURL的指針(有些像返回FILE類型的指針一樣). 相應(yīng)的在調(diào)用結(jié)束時要用curl_easy_cleanup函數(shù)清理.
一般curl_easy_init意味著一個會話的開始. 它會返回一個easy_handle(CURL*對象), 一般都用在easy系列的函數(shù)中.

5 void curl_easy_cleanup(CURL *handle);
描述:
這個調(diào)用用來結(jié)束一個會話.與curl_easy_init配合著用. 
參數(shù):
CURL類型的指針.

6 CURLcode curl_easy_setopt(CURL *handle, CURLoption option, parameter);
描述: 這個函數(shù)最重要了.幾乎所有的curl 程序都要頻繁的使用它.它告訴curl庫.程序?qū)⒂腥绾蔚男袨? 比如要查看一個網(wǎng)頁的html代碼等.(這個函數(shù)有些像ioctl函數(shù))參數(shù):
1 CURL類型的指針
2 各種CURLoption類型的選項.(都在curl.h庫里有定義,man 也可以查看到)
3 parameter 這個參數(shù) 既可以是個函數(shù)的指針,也可以是某個對象的指針,也可以是個long型的變量.它用什么這取決于第二個參數(shù).
CURLoption 這個參數(shù)的取值很多.具體的可以查看man手冊.

7 CURLcode curl_easy_perform(CURL *handle);
描述:這個函數(shù)在初始化CURL類型的指針 以及curl_easy_setopt完成后調(diào)用. 就像字面的意思所說perform就像是個舞臺.讓我們設(shè)置的
option 運作起來.參數(shù):
CURL類型的指針.

三、 curl_easy_setopt函數(shù)部分選項介紹
本節(jié)主要介紹curl_easy_setopt中跟http相關(guān)的參數(shù)。該函數(shù)是curl中非常重要的函數(shù),curl所有設(shè)置都是在該函數(shù)中完成的,該函數(shù)的設(shè)置選項眾多,注意本節(jié)的闡述的只是部分常見選項。
1.     CURLOPT_URL 
設(shè)置訪問URL

2.       CURLOPT_WRITEFUNCTION,CURLOPT_WRITEDATA
回調(diào)函數(shù)原型為:size_t function( void *ptr, size_t size, size_t nmemb, void *stream); 函數(shù)將在libcurl接收到數(shù)據(jù)后被調(diào)用,因此函數(shù)多做數(shù)據(jù)保存的功能,如處理下載文件。CURLOPT_WRITEDATA 用于表明CURLOPT_WRITEFUNCTION函數(shù)中的stream指針的來源。
如果你沒有通過CURLOPT_WRITEFUNCTION屬性給easy handle設(shè)置回調(diào)函數(shù),libcurl會提供一個默認(rèn)的回調(diào)函數(shù),它只是簡單的將接收到的數(shù)據(jù)打印到標(biāo)準(zhǔn)輸出。你也可以通過 CURLOPT_WRITEDATA屬性給默認(rèn)回調(diào)函數(shù)傳遞一個已經(jīng)打開的文件指針,用于將數(shù)據(jù)輸出到文件里。

3.      CURLOPT_HEADERFUNCTION,CURLOPT_HEADERDATA
回調(diào)函數(shù)原型為 size_t function( void *ptr, size_t size,size_t nmemb, void *stream); libcurl一旦接收到http 頭部數(shù)據(jù)后將調(diào)用該函數(shù)。CURLOPT_WRITEDATA 傳遞指針給libcurl,該指針表明CURLOPT_HEADERFUNCTION 函數(shù)的stream指針的來源。

4.       CURLOPT_READFUNCTION CURLOPT_READDATA
libCurl需要讀取數(shù)據(jù)傳遞給遠(yuǎn)程主機(jī)時將調(diào)用CURLOPT_READFUNCTION指定的函數(shù),函數(shù)原型是:size_t function(void *ptr, size_t size, size_t nmemb,void *stream). CURLOPT_READDATA 表明CURLOPT_READFUNCTION函數(shù)原型中的stream指針來源。

5.       CURLOPT_NOPROGRESS,CURLOPT_PROGRESSFUNCTION,CURLOPT_PROGRESSDATA
跟數(shù)據(jù)傳輸進(jìn)度相關(guān)的參數(shù)。CURLOPT_PROGRESSFUNCTION 指定的函數(shù)正常情況下每秒被libcurl調(diào)用一次,為了使CURLOPT_PROGRESSFUNCTION被調(diào)用,CURLOPT_NOPROGRESS必須被設(shè)置為false,CURLOPT_PROGRESSDATA指定的參數(shù)將作為CURLOPT_PROGRESSFUNCTION指定函數(shù)的第一個參數(shù)

6.       CURLOPT_TIMEOUT,CURLOPT_CONNECTIONTIMEOUT:
CURLOPT_TIMEOUT 由于設(shè)置傳輸時間,CURLOPT_CONNECTIONTIMEOUT 設(shè)置連接等待時間

7.       CURLOPT_FOLLOWLOCATION
設(shè)置重定位URL

8.       CURLOPT_RANGE: CURLOPT_RESUME_FROM:
斷點續(xù)傳相關(guān)設(shè)置。CURLOPT_RANGE 指定char *參數(shù)傳遞給libcurl,用于指明http域的RANGE頭域,例如:
表示頭500個字節(jié):bytes=0-499
表示第二個500字節(jié):bytes=500-999
表示最后500個字節(jié):bytes=-500
表示500字節(jié)以后的范圍:bytes=500-
第一個和最后一個字節(jié):bytes=0-0,-1
同時指定幾個范圍:bytes=500-600,601-999
CURLOPT_RESUME_FROM 傳遞一個long參數(shù)給libcurl,指定你希望開始傳遞的 偏移量。

四、 curl_easy_perform 函數(shù)說明(error 狀態(tài)碼)
該函數(shù)是完成curl_easy_setopt指定的所有選項,本節(jié)重點介紹curl_easy_perform的返回值。返回0意味一切ok,非0代表錯誤發(fā)生。主要錯誤碼說明:
1.    CURLE_OK 
    任務(wù)完成一切都好
2     CURLE_UNSUPPORTED_PROTOCOL
    不支持的協(xié)議,由URL的頭部指定
3     CURLE_COULDNT_CONNECT
    不能連接到remote 主機(jī)或者代理
4     CURLE_REMOTE_ACCESS_DENIED
    訪問被拒絕
5     CURLE_HTTP_RETURNED_ERROR
    Http返回錯誤
6     CURLE_READ_ERROR
讀本地文件錯誤
要獲取詳細(xì)的錯誤描述字符串,可以通過const char *curl_easy_strerror(CURLcode errornum ) 這個函數(shù)取得.
 

五、libcurl使用的HTTP消息頭
    當(dāng)使用libcurl發(fā)送http請求時,它會自動添加一些http頭。我們可以通過CURLOPT_HTTPHEADER屬性手動替換、添加或刪除相應(yīng) 的HTTP消息頭。
    Host
    http1.1(大部分http1.0)版本都要求客戶端請求提供這個信息頭。
    Pragma
    "no-cache"。表示不要緩沖數(shù)據(jù)。
    Accept
    "*/*"。表示允許接收任何類型的數(shù)據(jù)。
    Expect
    以POST的方式向HTTP服務(wù)器提交請求時,libcurl會設(shè)置該消息頭為"100-continue",它要求服務(wù)器在正式處理該請求之前,返回一 個"OK"消息。如果POST的數(shù)據(jù)很小,libcurl可能不會設(shè)置該消息頭。
自定義選項
    當(dāng)前越來越多的協(xié)議都構(gòu)建在HTTP協(xié)議之上(如:soap),這主要歸功于HTTP的可靠性,以及被廣泛使用的代理支持(可以穿透大部分防火墻)。 這些協(xié)議的使用方式與傳統(tǒng)HTTP可能有很大的不同。對此,libcurl作了很好的支持。
    自定義請求方式(CustomRequest)
    HTTP支持GET, HEAD或者POST提交請求??梢栽O(shè)置CURLOPT_CUSTOMREQUEST來設(shè)置自定義的請求方式,libcurl默認(rèn)以GET方式提交請求:
    curl_easy_setopt(easy_handle, CURLOPT_CUSTOMREQUEST, "MYOWNREQUEST"); 

修改消息頭
    HTTP協(xié)議提供了消息頭,請求消息頭用于告訴服務(wù)器如何處理請求;響應(yīng)消息頭則告訴瀏覽器如何處理接收到的數(shù)據(jù)。在libcurl中,你可以自由的添加 這些消息頭:

struct curl_slist *headers=NULL; /* init to NULL is important */

headers = curl_slist_append(headers, "Hey-server-hey: how are you?");

headers = curl_slist_append(headers, "X-silly-content: yes");

/* pass our list of custom made headers */

curl_easy_setopt(easyhandle, CURLOPT_HTTPHEADER, headers);

curl_easy_perform(easyhandle); /* transfer http */

curl_slist_free_all(headers); /* free the header list */

對于已經(jīng)存在的消息頭,可以重新設(shè)置它的值:

headers = curl_slist_append(headers, "Accept: Agent-007"); 
headers = curl_slist_append(headers, "Host: munged.host.line"); 

刪除消息頭
對于一個已經(jīng)存在的消息頭,設(shè)置它的內(nèi)容為空,libcurl在發(fā)送請求時就不會同時提交該消息頭:

headers = curl_slist_append(headers, "Accept:");

 

六、獲取http應(yīng)答頭信息

    發(fā)出http請求后,服務(wù)器會返回應(yīng)答頭信息和應(yīng)答數(shù)據(jù),如果僅僅是打印應(yīng)答頭的所有內(nèi)容,則直接可以通過curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, 打印函數(shù))的方式來完成,這里需要獲取的是應(yīng)答頭中特定的信息,比如應(yīng)答碼、cookies列表等,則需要通過下面這個函數(shù):
    CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ... ); 
    info參數(shù)就是我們需要獲取的內(nèi)容,下面是一些參數(shù)值:
    1.CURLINFO_RESPONSE_CODE
    獲取應(yīng)答碼
    2.CURLINFO_HEADER_SIZE
    頭大小
    3.CURLINFO_COOKIELIST
    cookies列表

    除了獲取應(yīng)答信息外,這個函數(shù)還能獲取curl的一些內(nèi)部信息,如請求時間、連接時間等等。

    更多的參數(shù)可以參考API文檔。

 

七、多線程問題
    首先一個基本原則就是:絕對不應(yīng)該在線程之間共享同一個libcurl handle(CURL *對象),不管是easy handle還是multi handle(本文只介紹easy_handle)。一個線程每次只能使用一個handle。
    libcurl是線程安全的,但有兩點例外:信號(signals)和SSL/TLS handler。 信號用于超時失效名字解析(timing out name resolves)。libcurl依賴其他的庫來支持SSL/STL,所以用多線程的方式訪問HTTPS或FTPS的URL時,應(yīng)該滿足這些庫對多線程 操作的一些要求。詳細(xì)可以參考:
    OpenSSL: http://www.openssl.org/docs/crypto/threads.html#DESCRIPTION

    GnuTLS: http://www.gnu.org/software/gnutls/manual/html_node/Multi_002dthreaded-applications.html

    NSS: 宣稱是多線程安全的。

八、什么時候libcurl無法正常工作
    傳輸失敗總是有原因的。你可能錯誤的設(shè)置了一些libcurl的屬性或者沒有正確的理解某些屬性的含義,或者是遠(yuǎn)程主機(jī)返回一些無法被正確解析的內(nèi)容。
    這里有一個黃金法則來處理這些問題:將CURLOPT_VERBOSE屬性設(shè)置為1,libcurl會輸出通信過程中的一些細(xì)節(jié)。如果使用的是http協(xié) 議,請求頭/響應(yīng)頭也會被輸出。將CURLOPT_HEADER設(shè)為1,這些頭信息將出現(xiàn)在消息的內(nèi)容中。
    當(dāng)然不可否認(rèn)的是,libcurl還存在bug。
    如果你對相關(guān)的協(xié)議了解越多,在使用libcurl時,就越不容易犯錯。

九、關(guān)于密碼
    客戶端向服務(wù)器發(fā)送請求時,許多協(xié)議都要求提供用戶名與密碼。libcurl提供了多種方式來設(shè)置它們。
    一些協(xié)議支持在URL中直接指定用戶名和密碼,類似于: protocol://user:[email protected]/path/。libcurl能正確的識別這種URL中的用戶名與密碼并執(zhí)行 相應(yīng)的操作。如果你提供的用戶名和密碼中有特殊字符,首先應(yīng)該對其進(jìn)行URL編碼。
    也可以通過CURLOPT_USERPWD屬性來設(shè)置用戶名與密碼。參數(shù)是格式如 “user:password ”的字符串:
    curl_easy_setopt(easy_handle, CURLOPT_USERPWD, "user_name:password")
    有時候在訪問代理服務(wù)器的時候,可能時時要求提供用戶名和密碼進(jìn)行用戶身份驗證。這種情況下,libcurl提供了另 一個屬性CURLOPT_PROXYUSERPWD:
    curl_easy_setopt(easy_handle, CURLOPT_PROXYUSERPWD, "user_name:password"); 
    在UNIX平臺下,訪問FTP的用戶名和密碼可能會被保存在$HOME/.netrc文件中。libcurl支持直接從這個文件中獲取用戶名與密碼:
    curl_easy_setopt(easy_handle, CURLOPT_NETRC, 1L); 
    在使用SSL時,可能需要提供一個私鑰用于數(shù)據(jù)安全傳輸,通過CURLOPT_KEYPASSWD來設(shè)置私鑰:
    curl_easy_setopt(easy_handle, CURLOPT_KEYPASSWD, "keypassword");

十、HTTP驗證
    在使用HTTP協(xié)議時,客戶端有很多種方式向服務(wù)器提供驗證信息。默認(rèn)的 HTTP驗證方法是"Basic”,它將用戶名與密碼以明文的方式、經(jīng)Base64編碼后保存在HTTP請求頭中,發(fā)往服務(wù)器。當(dāng)然這不太安全。
    當(dāng)前版本的libcurl支持的驗證方法有:basic, Digest, NTLM, Negotiate, GSS-Negotiate and SPNEGO。(譯者感嘆:搞Web這么多年,盡然不知道這些Http的驗證方式,實在慚愧。)可以通過CURLOPT_HTTPAUTH屬性來設(shè)置具體 的驗證方式:
    curl_easy_setopt(easy_handle, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST);
    向代理服務(wù)器發(fā)送驗證信息時,可以通過CURLOPT_PROXYAUTH設(shè)置驗證方式:
    curl_easy_setopt(easy_handle, CURLOPT_PROXYAUTH, CURLAUTH_NTLM);
    也可以同時設(shè)置多種驗證方式(通過按位與), 使用‘CURLAUTH_ANY‘將允許libcurl可以選擇任何它所支持的驗證方式。通過CURLOPT_HTTPAUTH或 CURLOPT_PROXYAUTH屬性設(shè)置的多種驗證方式,libcurl會在運行時選擇一種它認(rèn)為是最好的方式與服務(wù)器通信:
    curl_easy_setopt(easy_handle, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST|CURLAUTH_BASIC); 
    // curl_easy_setopt(easy_handle, CURLOPT_HTTPAUTH, CURLAUTH_ANY);

應(yīng)用實例

  1. #ifndef __HTTP_CURL_H__  
  2. #define __HTTP_CURL_H__  
  3.   
  4. #include <string>  
  5.   
  6. class CHttpClient  
  7. {  
  8. public:  
  9.     CHttpClient(void);  
  10.     ~CHttpClient(void);  
  11.   
  12. public:  
  13.     /** 
  14.     * @brief HTTP POST請求 
  15.     * @param strUrl 輸入?yún)?shù),請求的Url地址,如:http://www.baidu.com 
  16.     * @param strPost 輸入?yún)?shù),使用如下格式para1=val1?2=val2&… 
  17.     * @param strResponse 輸出參數(shù),返回的內(nèi)容 
  18.     * @return 返回是否Post成功 
  19.     */  
  20.     int Post(const std::string & strUrl, const std::string & strPost, std::string & strResponse);  
  21.   
  22.     /** 
  23.     * @brief HTTP GET請求 
  24.     * @param strUrl 輸入?yún)?shù),請求的Url地址,如:http://www.baidu.com 
  25.     * @param strResponse 輸出參數(shù),返回的內(nèi)容 
  26.     * @return 返回是否Post成功 
  27.     */  
  28.     int Get(const std::string & strUrl, std::string & strResponse);  
  29.   
  30.     /** 
  31.     * @brief HTTPS POST請求,無證書版本 
  32.     * @param strUrl 輸入?yún)?shù),請求的Url地址,如:https://www.alipay.com 
  33.     * @param strPost 輸入?yún)?shù),使用如下格式para1=val1?2=val2&… 
  34.     * @param strResponse 輸出參數(shù),返回的內(nèi)容 
  35.     * @param pCaPath 輸入?yún)?shù),為CA證書的路徑.如果輸入為NULL,則不驗證服務(wù)器端證書的有效性. 
  36.     * @return 返回是否Post成功 
  37.     */  
  38.     int Posts(const std::string & strUrl, const std::string & strPost, std::string & strResponse, const char * pCaPath = NULL);  
  39.   
  40.     /** 
  41.     * @brief HTTPS GET請求,無證書版本 
  42.     * @param strUrl 輸入?yún)?shù),請求的Url地址,如:https://www.alipay.com 
  43.     * @param strResponse 輸出參數(shù),返回的內(nèi)容 
  44.     * @param pCaPath 輸入?yún)?shù),為CA證書的路徑.如果輸入為NULL,則不驗證服務(wù)器端證書的有效性. 
  45.     * @return 返回是否Post成功 
  46.     */  
  47.     int Gets(const std::string & strUrl, std::string & strResponse, const char * pCaPath = NULL);  
  48.   
  49. public:  
  50.     void SetDebug(bool bDebug);  
  51.   
  52. private:  
  53.     bool m_bDebug;  
  54. };  
  55.   
  56. #endif  

具體實現(xiàn)的CPP

  1. #include "httpclient.h"  
  2. #include "curl/curl.h"  
  3. #include <string>  
  4.   
  5. CHttpClient::CHttpClient(void) :   
  6. m_bDebug(false)  
  7. {  
  8.   
  9. }  
  10.   
  11. CHttpClient::~CHttpClient(void)  
  12. {  
  13.   
  14. }  
  15.   
  16. static int OnDebug(CURL *, curl_infotype itype, char * pData, size_t size, void *)  
  17. {  
  18.     if(itype == CURLINFO_TEXT)  
  19.     {  
  20.         //printf("[TEXT]%s\n", pData);  
  21.     }  
  22.     else if(itype == CURLINFO_HEADER_IN)  
  23.     {  
  24.         printf("[HEADER_IN]%s\n", pData);  
  25.     }  
  26.     else if(itype == CURLINFO_HEADER_OUT)  
  27.     {  
  28.         printf("[HEADER_OUT]%s\n", pData);  
  29.     }  
  30.     else if(itype == CURLINFO_DATA_IN)  
  31.     {  
  32.         printf("[DATA_IN]%s\n", pData);  
  33.     }  
  34.     else if(itype == CURLINFO_DATA_OUT)  
  35.     {  
  36.         printf("[DATA_OUT]%s\n", pData);  
  37.     }  
  38.     return 0;  
  39. }  
  40.   
  41. static size_t OnWriteData(void* buffer, size_t size, size_t nmemb, void* lpVoid)  
  42. {  
  43.     std::string* str = dynamic_cast<std::string*>((std::string *)lpVoid);  
  44.     if( NULL == str || NULL == buffer )  
  45.     {  
  46.         return -1;  
  47.     }  
  48.   
  49.     char* pData = (char*)buffer;  
  50.     str->append(pData, size * nmemb);  
  51.     return size * nmemb;  
  52. }  
  53.   
  54. int CHttpClient::Post(const std::string & strUrl, const std::string & strPost, std::string & strResponse)  
  55. {  
  56.     CURLcode res;  
  57.     CURL* curl = curl_easy_init();  
  58.     if(NULL == curl)  
  59.     {  
  60.         return CURLE_FAILED_INIT;  
  61.     }  
  62.     if(m_bDebug)  
  63.     {  
  64.         curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);  
  65.         curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, OnDebug);  
  66.     }  
  67.     curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str());  
  68.     curl_easy_setopt(curl, CURLOPT_POST, 1);  
  69.     curl_easy_setopt(curl, CURLOPT_POSTFIELDS, strPost.c_str());  
  70.     curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);  
  71.     curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, OnWriteData);  
  72.     curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&strResponse);  
  73.     curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);  
  74.     curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 3);  
  75.     curl_easy_setopt(curl, CURLOPT_TIMEOUT, 3);  
  76.     res = curl_easy_perform(curl);  
  77.     curl_easy_cleanup(curl);  
  78.     return res;  
  79. }  
  80.   
  81. int CHttpClient::Get(const std::string & strUrl, std::string & strResponse)  
  82. {  
  83.     CURLcode res;  
  84.     CURL* curl = curl_easy_init();  
  85.     if(NULL == curl)  
  86.     {  
  87.         return CURLE_FAILED_INIT;  
  88.     }  
  89.     if(m_bDebug)  
  90.     {  
  91.         curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);  
  92.         curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, OnDebug);  
  93.     }  
  94.     curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str());  
  95.     curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);  
  96.     curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, OnWriteData);  
  97.     curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&strResponse);  
  98.     /** 
  99.     * 當(dāng)多個線程都使用超時處理的時候,同時主線程中有sleep或是wait等操作。 
  100.     * 如果不設(shè)置這個選項,libcurl將會發(fā)信號打斷這個wait從而導(dǎo)致程序退出。 
  101.     */  
  102.     curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);  
  103.     curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 3);  
  104.     curl_easy_setopt(curl, CURLOPT_TIMEOUT, 3);  
  105.     res = curl_easy_perform(curl);  
  106.     curl_easy_cleanup(curl);  
  107.     return res;  
  108. }  
  109.   
  110. int CHttpClient::Posts(const std::string & strUrl, const std::string & strPost, std::string & strResponse, const char * pCaPath)  
  111. {  
  112.     CURLcode res;  
  113.     CURL* curl = curl_easy_init();  
  114.     if(NULL == curl)  
  115.     {  
  116.         return CURLE_FAILED_INIT;  
  117.     }  
  118.     if(m_bDebug)  
  119.     {  
  120.         curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);  
  121.         curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, OnDebug);  
  122.     }  
  123.     curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str());  
  124.     curl_easy_setopt(curl, CURLOPT_POST, 1);  
  125.     curl_easy_setopt(curl, CURLOPT_POSTFIELDS, strPost.c_str());  
  126.     curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);  
  127.     curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, OnWriteData);  
  128.     curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&strResponse);  
  129.     curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);  
  130.     if(NULL == pCaPath)  
  131.     {  
  132.         curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);  
  133.         curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false);  
  134.     }  
  135.     else  
  136.     {  
  137.         //缺省情況就是PEM,所以無需設(shè)置,另外支持DER  
  138.         //curl_easy_setopt(curl,CURLOPT_SSLCERTTYPE,"PEM");  
  139.         curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, true);  
  140.         curl_easy_setopt(curl, CURLOPT_CAINFO, pCaPath);  
  141.     }  
  142.     curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 3);  
  143.     curl_easy_setopt(curl, CURLOPT_TIMEOUT, 3);  
  144.     res = curl_easy_perform(curl);  
  145.     curl_easy_cleanup(curl);  
  146.     return res;  
  147. }  
  148.   
  149. int CHttpClient::Gets(const std::string & strUrl, std::string & strResponse, const char * pCaPath)  
  150. {  
  151.     CURLcode res;  
  152.     CURL* curl = curl_easy_init();  
  153.     if(NULL == curl)  
  154.     {  
  155.         return CURLE_FAILED_INIT;  
  156.     }  
  157.     if(m_bDebug)  
  158.     {  
  159.         curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);  
  160.         curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, OnDebug);  
  161.     }  
  162.     curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str());  
  163.     curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);  
  164.     curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, OnWriteData);  
  165.     curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&strResponse);  
  166.     curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);  
  167.     if(NULL == pCaPath)  
  168.     {  
  169.         curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);  
  170.         curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false);  
  171.     }  
  172.     else  
  173.     {  
  174.         curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, true);  
  175.         curl_easy_setopt(curl, CURLOPT_CAINFO, pCaPath);  
  176.     }  
  177.     curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 3);  
  178.     curl_easy_setopt(curl, CURLOPT_TIMEOUT, 3);  
  179.     res = curl_easy_perform(curl);  
  180.     curl_easy_cleanup(curl);  
  181.     return res;  
  182. }  
  183.   
  184. ///////////////////////////////////////////////////////////////////////////////////////////////  
  185.   
  186. void CHttpClient::SetDebug(bool bDebug)  
  187. {  
  188.     m_bDebug = bDebug;  
  189. }