天天看點

(轉)libcurl庫使用方法,好長,好詳細。

一、ibcurl作為是一個多協定的便于用戶端使用的URL傳輸庫,基于C語言,提供C語言的API接口,支援DICT, FILE, FTP, FTPS, Gopher, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, POP3, POP3S, RTMP, RTSP, SCP, SFTP, SMTP, SMTPS, Telnet and TFTP這些協定,同時支援使用SSL證書的安全檔案傳輸:HTTP POST, HTTP PUT, FTP 上傳, 基于HTTP形式的上傳、代理、Cookies、使用者加密碼的認證等多種應用場景。另外,libcurl是一個高移植性的庫,能在絕大多數系統上運作,包括Solaris, NetBSD, FreeBSD, OpenBSD, Darwin, HPUX, IRIX, AIX, Tru64, Linux, UnixWare, HURD, Windows, Amiga, OS/2, BeOs, Mac OS X, Ultrix, QNX, OpenVMS, RISC OS, Novell NetWare, DOS等。

二、使用步驟

1. 調用curl_global_init()初始化libcurl

2. 調用curl_easy_init()函數得到 easy interface型指針

3. 調用curl_easy_setopt()設定傳輸選項

4. 根據curl_easy_setopt()設定的傳輸選項,實作回調函數以完成使用者特定任務

5. 調用curl_easy_perform()函數完成傳輸任務

6. 調用curl_easy_cleanup()釋放記憶體

7.調用curl_global_cleanup()析構libcurl

在整過過程中設定curl_easy_setopt()參數是最關鍵的,幾乎所有的libcurl程式都要使用它。

在基于LibCurl的程式裡,主要采用callback function (回調函數)的形式完成傳輸任務,使用者在啟動傳輸前設定好各類參數和回調函數,當滿足條件時libcurl将調用使用者的回調函數實作特定功能。

三、函數說明

1.CURLcode curl_global_init(long flags);

描述:

這個函數隻能用一次。(其實在調用curl_global_cleanup 函數後仍然可再用)

如果這個函數在curl_easy_init函數調用時還沒調用,它講由libcurl庫自動調用,是以多線程下最好主動調用該函數以防止線上程中curl_easy_init時多次調用。

注意:雖然libcurl是線程安全的,但curl_global_init是不能保證線程安全的,是以不要在每個線程中都調用curl_global_init,應該将該函數的調用放在主線程中。

參數:flags

CURL_GLOBAL_ALL                      //初始化所有的可能的調用。

CURL_GLOBAL_SSL                      //初始化支援 安全套接字層。

CURL_GLOBAL_WIN32            //初始化win32套接字庫。

CURL_GLOBAL_NOTHING         //沒有額外的初始化。

2 void curl_global_cleanup(void);

描述:在結束libcurl使用的時候,用來對curl_global_init做的工作清理。類似于close的函數。

注意:雖然libcurl是線程安全的,但curl_global_cleanup是不能保證線程安全的,是以不要在每個線程中都調用curl_global_init,應該将該函數的調用放在主線程中。

3 char *curl_version( );

描述: 列印目前libcurl庫的版本。

4 CURL *curl_easy_init( );

描述:

curl_easy_init用來初始化一個CURL的指針(有些像傳回FILE類型的指針一樣). 相應的在調用結束時要用curl_easy_cleanup函數清理.

一般curl_easy_init意味着一個會話的開始. 它會傳回一個easy_handle(CURL*對象), 一般都用在easy系列的函數中.

5 void curl_easy_cleanup(CURL *handle);

描述:

這個調用用來結束一個會話.與curl_easy_init配合着用. 

參數:

CURL類型的指針.

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

描述: 這個函數最重要了.幾乎所有的curl 程式都要頻繁的使用它.它告訴curl庫.程式将有如何的行為. 比如要檢視一個網頁的html代碼等.(這個函數有些像ioctl函數)參數:

1 CURL類型的指針

2 各種CURLoption類型的選項.(都在curl.h庫裡有定義,man 也可以檢視到)

3 parameter 這個參數 既可以是個函數的指針,也可以是某個對象的指針,也可以是個long型的變量.它用什麼這取決于第二個參數.

CURLoption 這個參數的取值很多.具體的可以檢視man手冊.

7 CURLcode curl_easy_perform(CURL *handle);

描述:這個函數在初始化CURL類型的指針 以及curl_easy_setopt完成後調用. 就像字面的意思所說perform就像是個舞台.讓我們設定的

option 運作起來.參數:

CURL類型的指針.

8 void curl_global_cleanup(void);

釋放libcurl

四、curl_easy_setopt函數部分選項介紹

本節主要介紹curl_easy_setopt中跟http相關的參數。該函數是curl中非常重要的函數,curl所有設定都是在該函數中完成的,該函數的設定選項衆多,注意本節的闡述的隻是部分常見選項。

     CURLOPT_URL 

設定通路URL

       CURLOPT_WRITEFUNCTION,CURLOPT_WRITEDATA

回調函數原型為:size_t function( void *ptr, size_t size, size_t nmemb, void *stream); 函數将在libcurl接收到資料後被調用,是以函數多做資料儲存的功能,如處理下載下傳檔案。CURLOPT_WRITEDATA 用于表明CURLOPT_WRITEFUNCTION函數中的stream指針的來源。

如果你沒有通過CURLOPT_WRITEFUNCTION屬性給easy handle設定回調函數,libcurl會提供一個預設的回調函數,它隻是簡單的将接收到的資料列印到标準輸出。你也可以通過 CURLOPT_WRITEDATA屬性給預設回調函數傳遞一個已經打開的檔案指針,用于将資料輸出到檔案裡。

      CURLOPT_HEADERFUNCTION,CURLOPT_HEADERDATA

回調函數原型為 size_t function( void *ptr, size_t size,size_t nmemb, void *stream); libcurl一旦接收到http 頭部資料後将調用該函數。CURLOPT_WRITEDATA 傳遞指針給libcurl,該指針表明CURLOPT_HEADERFUNCTION 函數的stream指針的來源。

       CURLOPT_READFUNCTION CURLOPT_READDATA

libCurl需要讀取資料傳遞給遠端主機時将調用CURLOPT_READFUNCTION指定的函數,函數原型是:size_t function(void *ptr, size_t size, size_t nmemb,void *stream). CURLOPT_READDATA 表明CURLOPT_READFUNCTION函數原型中的stream指針來源。

       CURLOPT_NOPROGRESS,CURLOPT_PROGRESSFUNCTION,CURLOPT_PROGRESSDATA

跟資料傳輸進度相關的參數。CURLOPT_PROGRESSFUNCTION 指定的函數正常情況下每秒被libcurl調用一次,為了使CURLOPT_PROGRESSFUNCTION被調用,CURLOPT_NOPROGRESS必須被設定為false,CURLOPT_PROGRESSDATA指定的參數将作為CURLOPT_PROGRESSFUNCTION指定函數的第一個參數

       CURLOPT_TIMEOUT,CURLOPT_CONNECTIONTIMEOUT:

CURLOPT_TIMEOUT 由于設定傳輸時間,CURLOPT_CONNECTIONTIMEOUT 設定連接配接等待時間

      CURLOPT_FOLLOWLOCATION

設定重定位URL

       CURLOPT_RANGE: CURLOPT_RESUME_FROM:

斷點續傳相關設定。CURLOPT_RANGE 指定char *參數傳遞給libcurl,用于指明http域的RANGE頭域,例如:

表示頭500個位元組:bytes=0-499

表示第二個500位元組:bytes=500-999

表示最後500個位元組:bytes=-500

表示500位元組以後的範圍:bytes=500-

第一個和最後一個位元組:bytes=0-0,-1

同時指定幾個範圍:bytes=500-600,601-999

CURLOPT_RESUME_FROM 傳遞一個long參數給libcurl,指定你希望開始傳遞的 偏移量。

五、libcurl使用的HTTP消息頭

當使用libcurl發送http請求時,它會自動添加一些http頭。我們可以通過CURLOPT_HTTPHEADER屬性手動替換、添加或删除相應 的HTTP消息頭。

    Host

    http1.1(大部分http1.0)版本都要求用戶端請求提供這個資訊頭。

    Pragma

    "no-cache"。表示不要緩沖資料。

    Accept

    "*/*"。表示允許接收任何類型的資料。

    Expect

    以POST的方式向HTTP伺服器送出請求時,libcurl會設定該消息頭為"100-continue",它要求伺服器在正式處理該請求之前,傳回一 個"OK"消息。如果POST的資料很小,libcurl可能不會設定該消息頭。

自定義選項

    目前越來越多的協定都建構在HTTP協定之上(如:soap),這主要歸功于HTTP的可靠性,以及被廣泛使用的代理支援(可以穿透大部分防火牆)。 這些協定的使用方式與傳統HTTP可能有很大的不同。對此,libcurl作了很好的支援。

    自定義請求方式(CustomRequest)

    HTTP支援GET, HEAD或者POST送出請求。可以設定CURLOPT_CUSTOMREQUEST來設定自定義的請求方式,libcurl預設以GET方式送出請求:

    curl_easy_setopt(easy_handle, CURLOPT_CUSTOMREQUEST, "MYOWNREQUEST"); 

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 */

六、擷取http應答頭資訊

    發出http請求後,伺服器會傳回應答頭資訊和應答資料,如果僅僅是列印應答頭的所有内容,則直接可以通過curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, 列印函數)的方式來完成,這裡需要擷取的是應答頭中特定的資訊,比如應答碼、cookies清單等,則需要通過下面這個函數:

    CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ... ); 

    info參數就是我們需要擷取的内容,下面是一些參數值:

    1.CURLINFO_RESPONSE_CODE

    擷取應答碼

    2.CURLINFO_HEADER_SIZE

    頭大小

    3.CURLINFO_COOKIELIST

    cookies清單

除了擷取應答資訊外,這個函數還能擷取curl的一些内部資訊,如請求時間、連接配接時間等等。

七、多線程問題

    首先一個基本原則就是:絕對不應該線上程之間共享同一個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時,應該滿足這些庫對多線程 操作的一些要求。詳細可以參考:

    OpenSSL: http://www.openssl.org/docs/crypto/threads.html#DESCRIPTION

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

八、HTTP驗證

    在使用HTTP協定時,用戶端有很多種方式向伺服器提供驗證資訊。預設的 HTTP驗證方法是"Basic”,它将使用者名與密碼以明文的方式、經Base64編碼後儲存在HTTP請求頭中,發往伺服器。當然這不太安全。

    目前版本的libcurl支援的驗證方法有:basic, Digest, NTLM, Negotiate, GSS-Negotiate and SPNEGO。可以通過CURLOPT_HTTPAUTH屬性來設定具體 的驗證方式:

    curl_easy_setopt(easy_handle, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST);

    向代理伺服器發送驗證資訊時,可以通過CURLOPT_PROXYAUTH設定驗證方式:

    curl_easy_setopt(easy_handle, CURLOPT_PROXYAUTH, CURLAUTH_NTLM);

    也可以同時設定多種驗證方式(通過按位與), 使用‘CURLAUTH_ANY‘将允許libcurl可以選擇任何它所支援的驗證方式。通過CURLOPT_HTTPAUTH或 CURLOPT_PROXYAUTH屬性設定的多種驗證方式,libcurl會在運作時選擇一種它認為是最好的方式與伺服器通信:

    curl_easy_setopt(easy_handle, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST|CURLAUTH_BASIC); 

    // curl_easy_setopt(easy_handle, CURLOPT_HTTPAUTH, CURLAUTH_ANY);

九、編譯libcurl庫

從網站https://curl.haxx.se/download找到源碼包,官網最新版為7.56.0,但是這個壓縮包的curl-7.56.0\projects\Windows路徑下VC6-VC14各個版本的VS解決方案。

9.1 如果需要libcur支援https,需要openssl庫支援。

libcurl主要功能就是用不同的協定連接配接和溝通不同的伺服器,如果使用HTTPS,需要OpenSSL

libcurl https://curl.haxx.se/download.html 下載下傳Source Archives即可

ActiveState https://www.activestate.com/activeperl/downloads 下載下傳perl解析器,編譯openssl需要用到。

openssl https://www.openssl.org/source/ 下載下傳openssl-1.0.2k,1.1.0以後的檔案和安裝方法都換了。

zlib http://zlib.net/ 下載下傳1.2.7以外的版本,比如1.2.11。

支援https的libcurl庫編譯方法:

1)解壓

為了友善安裝,在D盤根目錄下建立一個名為libcurl-ssl的檔案夾,将下載下傳的三個壓縮包解壓到該檔案夾。

在 curl-7.54.0 -> lib 下建立檔案夾openssl用來存放openssl的頭檔案。

2) zlib編譯:

zlib-1.2.11\contrib\vstudio\vc14\zlibvc.sln,編譯release版本。

在生成的x86\ZlibDllRelease檔案夾中有zlibwapi.dll和zlibwapi.lib檔案

3) ActiveState安裝:

打開安裝包,選擇Modify預設安裝或Repair修改安裝路徑都可以

4) openssl編譯:

這是最麻煩、最容易出錯的一環了,因為他沒有項目檔案,隻能通過指令行來編譯。

在開始菜單中找到vs自帶的 VS2015 x86 本機工具指令提示符

使用cd指令進入到openssl-1.0.2k檔案夾中

指令行鍵入 perl Configure VC-WIN32 no-asm

指令行鍵入 ms\do_ms.bat

指令行鍵入 nmake -f ms/ntdll.mak

等待差不多五分鐘,隻要不出現“stop”,安全地執行到結束,就算成功。

一旦中間出了差錯,最好是把檔案夾也删了,重新解壓、配置編譯,如果你留有編譯失敗的半成品,它可能會告訴你“無法解析XXX”。

5) 将 openssl-1.0.2k -> inc32 -> openssl 所有的.h 和 openssl-1.0.2k -> out32dll 的 libeay32.lib、libeay32.dll、ssleay32.lib、ssleay32.dll 一起複制到 curl-7.54.0 -> lib -> openssl 中

libcurl編譯:

編譯平台選擇 DLL Debug - DLL OpenSSL

curl-7.54.0 ->projects -> Windows -> VC14 -> curl-all.sln,可能會提示更新工程,确定即可。

将 libcurl 設為啟動項目,選擇 libcurl -> Resource Files -> libcurl.rc,右鍵“移出”,它記錄着版本資訊,隻會增大檔案,可以移出掉。

選擇 屬性 -> C/C++ -> 預處理器 -> 預處理器定義,将"BUILDING_LIBCURL"改成"CURL_STATICLIB"。這樣那些接口函數就不會被聲明為導出函數了。

選擇 屬性 -> 連結器 -> 正常 -> 附加庫目錄 添加 ..\..\..\..\lib\openssl,指向curl-7.54.0 -> lib -> openssl

選擇 屬性 -> 連結器 -> 輸入 -> 附加依賴項 添加 libeay32.lib;ssleay32.lib;ws2_32.lib;wldap32.lib; 前兩個是為了OpenSSL,後兩個是CURL必須依賴的。

在編譯成功後 curl-7.54.0 -> build -> Win32 -> VC14 -> DLL Debug - DLL OpenSSL 檔案夾中會生成有 libcurld.dll 和 libcurld.lib(注意名字不是libcurl)。

9.2不支援https的libcurl庫編譯方法:

使用curl-7.32.0版本中vs工程,vc自動編譯。從網站https://curl.haxx.se/download 中下載下傳curl-7.32.0版本。解壓curl-7.32.0,找到vs工程目錄,比如:curl-7.32.0\vs\vc8\lib\vc8libcurl.vcproj

1) 打開curl-7.32.0\vs\vc8\lib\vc8libcurl.vcproj檔案,VS2010會提示更新工程,下一步即可。

VC工程裡有些設定問題導緻不能直接編譯,需要稍作修改

2) 打開工程屬性 > C\C++ > 正常 > 附加包含目錄。這裡的包含目錄是"..\include",而這個目錄根本就不存在,它應該指向"curl-7.32.0\include"才對,是以把這裡改成"..\..\..\include"。(或者直接完整路徑也可以)

3) 打開工程屬性 > C\C++ > 預處理器 > 預處理器定義。這裡有個預設宏"BUILDING_LIBCURL",如果要編譯生成靜态庫,則要把它改成"CURL_STATICLIB"。這樣,那些接口函數就不會被聲明為導出函數了。

4) 打開工程屬性 > C\C++ > 庫管理器 > 正常 > 附加依賴項。添加ws2_32.lib和wldap32.lib,這是CURL必須依賴的。或者在代碼中使用#pragma comment預編譯指令,手動引入這兩個lib庫。

9.3 libcurld.lib/libcurl.lib引用方法

将 curl-7.54.0 -> include 目錄下的curl檔案夾,複制過去。

将libcurl編譯的 libcurld.dll 和 libcurld.lib 複制到debug。

将libcurld.dll和之前OpenSSL生成的 libeay32.dll、ssleay32.dll 各複制一份到項目檔案夾下,否則會報錯。

選擇 配置屬性 -> C\C++ -> 預處理器 -> 預處理器定義,添加CURL_STATICLIB。

屬性中的 附加包含目錄、附加庫目錄和附加依賴項就在代碼中實作。

十、執行個體代碼

1 #define CURL_STATICLIB                //如果是靜态庫方式,需要包含這句
  2  
  3 #include "curl\curl.h"
  4 #include <iostream>
  5 #include <list>
  6 #include <string>
  7  
  8 #ifdef _DEBUG
  9 #pragma comment(lib,"libcurld.lib")
 10 #else
 11 #pragma comment(lib,"libcurl.lib")
 12 #endif
 13  
 14 #pragma comment ( lib, "ws2_32.lib" )
 15 #pragma comment ( lib, "winmm.lib" )
 16 #pragma comment ( lib, "wldap32.lib" )
 17 #pragma comment(lib, "Advapi32.lib")
 18  
 19  
 20 std::wstring AsciiToUnicode(const std::string& str)
 21 {
 22     // 預算-緩沖區中寬位元組的長度  
 23     int unicodeLen = MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, nullptr, 0);
 24     // 給指向緩沖區的指針變量配置設定記憶體  
 25     wchar_t *pUnicode = (wchar_t*)malloc(sizeof(wchar_t)*unicodeLen);
 26     // 開始向緩沖區轉換位元組  
 27     MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, pUnicode, unicodeLen);
 28     std::wstring ret_str = pUnicode;
 29     free(pUnicode);
 30     return ret_str;
 31 }
 32  
 33 std::string UnicodeToUtf8(const std::wstring& wstr)
 34 {
 35     // 預算-緩沖區中多位元組的長度  
 36     int ansiiLen = WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), -1, nullptr, 0, nullptr, nullptr);
 37     // 給指向緩沖區的指針變量配置設定記憶體  
 38     char *pAssii = (char*)malloc(sizeof(char)*ansiiLen);
 39     // 開始向緩沖區轉換位元組  
 40     WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), -1, pAssii, ansiiLen, nullptr, nullptr);
 41     std::string ret_str = pAssii;
 42     free(pAssii);
 43     return ret_str;
 44 }
 45  
 46 //ANSI轉UTF8
 47 std::string AsciiToUtf8(const std::string& str)
 48 {
 49     return UnicodeToUtf8(AsciiToUnicode(str));
 50 }
 51  
 52 //UTF8轉ANSI
 53 std::string Utf8toAscii(const std::string strUTF8)
 54 {
 55     std::string  strAnsi = "";
 56     //擷取轉換為多位元組後需要的緩沖區大小,建立多位元組緩沖區
 57     UINT nLen = MultiByteToWideChar(CP_UTF8, NULL, strUTF8.c_str(), -1, NULL, NULL);
 58     WCHAR *wszBuffer = new WCHAR[nLen + 1];
 59     nLen = MultiByteToWideChar(CP_UTF8, NULL, strUTF8.c_str(), -1, wszBuffer, nLen);
 60     wszBuffer[nLen] = 0;
 61     nLen = WideCharToMultiByte(936, NULL, wszBuffer, -1, NULL, NULL, NULL, NULL);
 62     CHAR *szBuffer = new CHAR[nLen + 1];
 63     nLen = WideCharToMultiByte(936, NULL, wszBuffer, -1, szBuffer, nLen, NULL, NULL);
 64     szBuffer[nLen] = 0;
 65     strAnsi = szBuffer;
 66     //清理記憶體
 67     delete[]szBuffer;
 68     delete[]wszBuffer;
 69     return strAnsi;
 70 }
 71  
 72 // reply of the requery  
 73 size_t req_reply(void *ptr, size_t size, size_t nmemb, void *stream)
 74 {
 75     if (stream == NULL || ptr == NULL || size == 0)
 76         return 0;
 77  
 78     size_t realsize = size * nmemb;
 79     std::string *buffer = (std::string*)stream;
 80     if (buffer != NULL)
 81     {
 82         buffer->append((const char *)ptr, realsize);
 83     }
 84     return realsize;
 85     /*
 86     std::string *str = (std::string*)stream;
 87     (*str).append((char*)ptr, size*nmemb);
 88     return size * nmemb;
 89     */
 90 }
 91  
 92 /*
 93 功能:get http資料
 94 參數:url:請求字元串。如果請求帶參數資料,直接拼湊到url後面;比如:http://127.0.0.1:8080/api/Accounts/Login?uername=admin&password=123
 95 listRequestHeader:請求頭資料清單。
 96 bResponseIsWithHeaderData:bool類型,表示響應體中是否包含應答頭資料。true,包含,false,不包含。如果包含的話,應答資料中包含Content-Type,Server等資訊。
 97 nConnectTimeout:連接配接逾時時間,機關為秒;
 98 nTimeout:讀寫資料逾時時間,機關為秒
 99 傳回值:CURLcode
100 */
101 CURLcode curl_get_req(const std::string &url, std::string &response, std::list<std::string> listRequestHeader, bool bResponseIsWithHeaderData = false, int nConnectTimeout = 10, int nTimeout = 10)
102 {
103     // init curl  
104     CURL *curl = curl_easy_init();
105     // res code  
106     CURLcode res;
107     if (curl)
108     {
109         // set params  
110         curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); // url  
111         //curl_easy_setopt(m_curl, CURLOPT_PORT, 8089);    //port
112         curl_easy_setopt(curl, CURLOPT_POST, 0); // get reqest 
113         //建構HTTP封包頭
114         struct curl_slist* headers = NULL;
115         if (listRequestHeader.size() > 0)
116         {
117             std::list<std::string>::iterator iter, iterEnd;
118             iter = listRequestHeader.begin();
119             iterEnd = listRequestHeader.end();
120             for (iter; iter != iterEnd; iter++)
121             {
122                 headers = curl_slist_append(headers, iter->c_str());
123             }
124             //headers = curl_slist_append(headers, "Content-Type:application/json;charset=UTF-8");
125             //headers = curl_slist_append(headers, "Content-Type:application/x-www-form-urlencoded");
126             if (headers != NULL)
127             {
128                 curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);//設定http請求頭資訊
129             }
130         }
131         curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false); // if want to use https  
132         curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false); // set peer and host verify false  
133         curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
134         curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);
135         curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, req_reply);
136         curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&response);
137         curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
138         if (bResponseIsWithHeaderData)
139         {
140             curl_easy_setopt(curl, CURLOPT_HEADER, 1);//響應體中是否包含了頭資訊,比如Content-Type:application/json;charset=UTF-8
141         }
142         curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, nConnectTimeout); // set transport and time out time  
143         curl_easy_setopt(curl, CURLOPT_TIMEOUT, nTimeout);
144         // start request  
145         res = curl_easy_perform(curl);
146         if (headers != NULL)
147         {
148             curl_slist_free_all(headers); //free the list again
149         }
150     }
151     // release curl  
152     curl_easy_cleanup(curl);
153     return res;
154 }
155  
156 CURLcode curl_get_req_ex(CURL *curl, const std::string &url, std::string &response, std::list<std::string> listRequestHeader, bool bResponseIsWithHeaderData = false, int nConnectTimeout = 10, int nTimeout = 10)
157 {
158     // res code  
159     CURLcode res;
160     if (curl)
161     {
162         // set params 
163                 curl_easy_reset(curl);
164         /* enable TCP keep-alive for this transfer */
165         curl_easy_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1L);
166         /* keep-alive idle time to 120 seconds */
167         curl_easy_setopt(curl, CURLOPT_TCP_KEEPIDLE, 120L);
168         /* interval time between keep-alive probes: 30 seconds */
169         curl_easy_setopt(curl, CURLOPT_TCP_KEEPINTVL, 30L);
170  
171         curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); // url  
172         //curl_easy_setopt(m_curl, CURLOPT_PORT, 8089);    //port
173         curl_easy_setopt(curl, CURLOPT_POST, 0); // get reqest 
174         //建構HTTP封包頭
175         struct curl_slist* headers = NULL;
176         if (listRequestHeader.size() > 0)
177         {
178             std::list<std::string>::iterator iter, iterEnd;
179             iter = listRequestHeader.begin();
180             iterEnd = listRequestHeader.end();
181             for (iter; iter != iterEnd; iter++)
182             {
183                 headers = curl_slist_append(headers, iter->c_str());
184             }
185             //headers = curl_slist_append(headers, "Content-Type:application/json;charset=UTF-8");
186             //headers = curl_slist_append(headers, "Content-Type:application/x-www-form-urlencoded");
187             if (headers != NULL)
188             {
189                 curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);//設定http請求頭資訊
190             }
191         }
192         curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false); // if want to use https  
193         curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false); // set peer and host verify false  
194         curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
195         curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);
196         curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, req_reply);
197         curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&response);
198         curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
199         if (bResponseIsWithHeaderData)
200         {
201             curl_easy_setopt(curl, CURLOPT_HEADER, 1);//響應體中是否包含了頭資訊,比如Content-Type:application/json;charset=UTF-8
202         }
203         curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, nConnectTimeout); // set transport and time out time  
204         curl_easy_setopt(curl, CURLOPT_TIMEOUT, nTimeout);
205         // start request  
206         res = curl_easy_perform(curl);
207         if (headers != NULL)
208         {
209             curl_slist_free_all(headers); //free the list again
210         }
211     }
212     return res;
213 }
214  
215 /*
216 功能:post http資料
217 參數:url:請求字元串,比如:http://127.0.0.1:8080/api/Accounts/Login
218 postParams:請求附帶的參數,比如uername=admin&password=123
219 listRequestHeader:請求頭資料清單。
220 bResponseIsWithHeaderData:bool類型,表示響應體中是否包含應答頭資料。true,包含,false,不包含。如果包含的話,應答資料中包含Content-Type,Server等資訊。
221 nConnectTimeout:連接配接逾時時間,機關為秒;
222 nTimeout:讀寫資料逾時時間,機關為秒
223 傳回值:CURLcode
224 */
225 CURLcode curl_post_req(const std::string &url, const std::string &postParams, std::string &response, std::list<std::string> listRequestHeader, bool bResponseIsWithHeaderData = false, int nConnectTimeout = 10, int nTimeout = 10)
226 {
227     // init curl  
228     CURL *curl = curl_easy_init();
229     // res code  
230     CURLcode res;
231     if (curl)
232     {
233         // set params  
234         curl_easy_setopt(curl, CURLOPT_POST, 1); // post req  
235         curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); // url  
236         //curl_easy_setopt(m_curl, CURLOPT_PORT, 8089);    //port
237         curl_easy_setopt(curl, CURLOPT_POST, 1); // post reqest 
238         //建構HTTP封包頭
239         struct curl_slist* headers = NULL;
240         if (listRequestHeader.size() > 0)
241         {
242             std::list<std::string>::iterator iter, iterEnd;
243             iter = listRequestHeader.begin();
244             iterEnd = listRequestHeader.end();
245             for (iter; iter != iterEnd; iter++)
246             {
247                 headers = curl_slist_append(headers, iter->c_str());
248             }
249             //headers = curl_slist_append(headers, "Content-Type:application/json;charset=UTF-8");
250             //headers = curl_slist_append(headers, "Content-Type:application/x-www-form-urlencoded");
251             if (headers != NULL)
252             {
253                 curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);//設定http請求頭資訊
254             }
255         }
256         else
257         {
258             headers = curl_slist_append(headers, "Content-Type:application/x-www-form-urlencoded");
259             if (headers != NULL)
260             {
261                 curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);//設定http請求頭資訊
262             }
263         }
264         curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postParams.c_str()); // params  
265         curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false); // if want to use https  
266         curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false); // set peer and host verify false  
267         curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
268         curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1); //傳回的頭部中有Location(一般直接請求的url沒找到),則繼續請求Location對應的資料 
269         curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);
270         curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, req_reply);
271         curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&response);
272         curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
273         if (bResponseIsWithHeaderData)
274         {
275             curl_easy_setopt(curl, CURLOPT_HEADER, 1);//響應體中是否包含了頭資訊,比如Content-Type:application/json;charset=UTF-8
276         }
277         curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, nConnectTimeout);
278         curl_easy_setopt(curl, CURLOPT_TIMEOUT, nTimeout);
279         // start request  
280         res = curl_easy_perform(curl);
281         if (headers != NULL)
282         {
283             curl_slist_free_all(headers); //free the list again
284         }
285     }
286     // release curl  
287     curl_easy_cleanup(curl);
288     return res;
289 }
290  
291 CURLcode curl_post_req_ex(CURL *curl, const std::string &url, const std::string &postParams, std::string &response, std::list<std::string> listRequestHeader, bool bResponseIsWithHeaderData = false, int nConnectTimeout = 10, int nTimeout = 10)
292 {
293     // res code  
294     CURLcode res;
295     if (curl)
296     {
297         // set params
298                 curl_easy_reset(curl);
299         /* enable TCP keep-alive for this transfer */
300         curl_easy_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1L);
301         /* keep-alive idle time to 120 seconds */
302         curl_easy_setopt(curl, CURLOPT_TCP_KEEPIDLE, 120L);
303         /* interval time between keep-alive probes: 30 seconds */
304         curl_easy_setopt(curl, CURLOPT_TCP_KEEPINTVL, 30L);
305  
306         curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); // url  
307         //curl_easy_setopt(m_curl, CURLOPT_PORT, 8089);    //port
308         curl_easy_setopt(curl, CURLOPT_POST, 1); // post reqest 
309         //建構HTTP封包頭
310         struct curl_slist* headers = NULL;
311         if (listRequestHeader.size() > 0)
312         {
313             std::list<std::string>::iterator iter, iterEnd;
314             iter = listRequestHeader.begin();
315             iterEnd = listRequestHeader.end();
316             for (iter; iter != iterEnd; iter++)
317             {
318                 headers = curl_slist_append(headers, iter->c_str());
319             }
320             //headers = curl_slist_append(headers, "Content-Type:application/json;charset=UTF-8");
321             //headers = curl_slist_append(headers, "Content-Type:application/x-www-form-urlencoded;charset=UTF-8");
322             if (headers != NULL)
323             {
324                 curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);//設定http請求頭資訊
325             }
326         }
327         else
328         {
329             headers = curl_slist_append(headers, "Content-Type:application/x-www-form-urlencoded");
330             if (headers != NULL)
331             {
332                 curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);//設定http請求頭資訊
333             }
334         }
335         curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postParams.c_str()); // params  
336         curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false); // if want to use https  
337         curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false); // set peer and host verify false  
338         curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
339         curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1); //傳回的頭部中有Location(一般直接請求的url沒找到),則繼續請求Location對應的資料 
340         curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);
341         curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, req_reply);
342         curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&response);
343         curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
344         if (bResponseIsWithHeaderData)
345         {
346             curl_easy_setopt(curl, CURLOPT_HEADER, 1);//響應體中是否包含了頭資訊,比如Content-Type:application/json;charset=UTF-8
347         }
348         curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, nConnectTimeout);
349         curl_easy_setopt(curl, CURLOPT_TIMEOUT, nTimeout);
350         // start request  
351         res = curl_easy_perform(curl);
352         if (headers != NULL)
353         {
354             curl_slist_free_all(headers); //free the list again
355         }
356     }
357     return res;
358 }
359  
360 //執行個體1
361     curl_global_init(CURL_GLOBAL_ALL);
362     
363     //post擷取資料
364     std::string strResponse = "",strResponseAnsi = "";
365         strResponse.clear();
366     CURLcode res = curl_post_req("http://127.0.0.1:8080/api/Accounts/Login", "username=admin&password=123", strResponse);
367     if (res == CURLE_OK)
368     {
369         std::string strToken = "";
370         strResponseAnsi = Utf8toAscii(strResponse);
371     }
372  
373     //get擷取資料
374         strResponse.clear();
375     res = curl_get_req("http://127.0.0.1:8080/api/Accounts/Login?username=admin&password=123", strResponse);
376     if (res == CURLE_OK)
377     {
378         int jj = 0;
379     }
380  
381     curl_global_cleanup();
382 //執行個體2    
383     //post json資料
384     CURL * curl = curl_easy_init();
385     std::string strResponse = "", strResponseAnsi = "";
386     char szRequestUrl[256] = { 0 };
387     CURLcode res = CURLE_OK;
388     sprintf_s(szRequestUrl, "%s/api/GPS/AddOne", "http://127.0.0.1:8080");
389     std::string strPostParams = "";
390     try
391     {
392         boost::property_tree::ptree ptroot;
393         ptroot.put("deviceid", "12345678");
394         ptroot.put<unsigned int>("deviceStatus", 0);
395         ptroot.put<unsigned int>("alarmFlag", 0);
396         ptroot.put("lng", fLongitude);
397         ptroot.put("lat", fLatitude);
398         ptroot.put("speed", 0);
399         ptroot.put("direction", 0);
400         ptroot.put<int>("altitude", 10);
401         ptroot.put("gpsTime", "2018-10-10 12:00:01");
402         std::stringstream sstream;
403         boost::property_tree::write_json(sstream, ptroot);
404         strPostParams = sstream.str();
405         bSuccess = true;
406     }
407     catch (boost::property_tree::ptree_error pt)
408     {
409         pt.what();
410     }
411     if (bSuccess)
412     {
413       std::string strAuthorization = "admin---";
414         std::string strRequestHeaders = strAuthorization;
415         std::list<std::string> listRequestHeader;
416         listRequestHeader.push_back(strRequestHeaders);
417         listRequestHeader.push_back("Content-Type:application/json;charset=UTF-8");
418         res = curl_post_req_ex(curl, szRequestUrl, strPostParams, strResponse, listRequestHeader);
419         if (res == CURLE_OK)
420         {
421             bSuccess = true;
422         }
423     }
424 
425 curl_easy_cleanup(curl);      

注意事項:

1、http模式測試,使用Postman插件或模拟測試網站 https://www.sojson.com/httpRequest/

2、保持長連接配接,設定選項。

 /* enable TCP keep-alive for this transfer */

        curl_easy_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1L);

        /* keep-alive idle time to 120 seconds */

        curl_easy_setopt(curl, CURLOPT_TCP_KEEPIDLE, 120L);

        /* interval time between keep-alive probes: 60 seconds */

        curl_easy_setopt(curl, CURLOPT_TCP_KEEPINTVL, 60L);

3、調用libcurl下載下傳,然後使用netstat檢視發現有大量的TCP連接配接保持在CLOSE_WAIT狀态

檢視libcurl的文檔說明,有這樣一個選項:

CURLOPT_FORBID_REUSE

Pass a long. Set to 1 to make the next transfer explicitly close the connection when done. Normally, libcurl keeps all connections alive when done with one transfer in case a succeeding one follows that can re-use them. This option should be used with caution and only if you understand what it does. Set to 0 to have libcurl keep the connection open for possible later re-use (default behavior).

也就是說,預設情況下libcurl完成一個任務以後,出于重用連接配接的考慮不會馬上關閉

如果沒有新的TCP請求來重用這個連接配接,那麼隻能等到CLOSE_WAIT逾時,這個時間預設在7200秒甚至更高,太多的CLOSE_WAIT連接配接會導緻性能問題

解決方法:

curl_easy_setopt(curl, CURLOPT_FORBID_REUSE, 1);

最好再修改一下TCP參數調低CLOSE_WAIT和TIME_WAIT的逾時時間

4、libcurl進行異步并發

使用multi接口,multi接口的使用會比easy 接口稍微複雜點,畢竟multi接口是依賴easy接口的,首先粗略的講下其使用流程:curl_multi _init初始化一個multi curl對象,為了同時進行多個curl的并發通路,我們需要初始化多個easy curl對象,使用curl_easy_setopt進行相關設定,然後調用curl_multi _add_handle把easy curl對象添加到multi curl對象中,添加完畢後執行curl_multi_perform方法進行并發的通路,通路結束後curl_multi_remove_handle移除相關easy curl對象,curl_easy_cleanup清除easy curl對象,最後curl_multi_cleanup清除multi curl對象。multi接口具體使用方法參考下面連結

https://blog.csdn.net/whui19890911/article/details/79320408

5、請求頭、響應頭多個參數設定。使用curl_slist_append函數一個個參數插入。

參考資料:

libcurl官網:https://curl.haxx.se/libcurl/

vc編譯libcurl:https://www.cnblogs.com/findumars/p/7496122.html

curl_errno錯誤碼說明

CURLE_UNSUPPORTED_PROTOCOL (1) – 您傳送給 libcurl 的網址使用了此 libcurl 不支援的協定。 可能是您沒有使用的編譯時選項造成了這種情況(可能是協定字元串拼寫有誤,或沒有指定協定 libcurl 代碼)。

CURLE_FAILED_INIT (2) – 非常早期的初始化代碼失敗。 可能是内部錯誤或問題。

CURLE_URL_MALFORMAT (3) – 網址格式不正确。

CURLE_COULDNT_RESOLVE_PROXY (5) – 無法解析代理伺服器。 指定的代理伺服器主機無法解析。

CURLE_COULDNT_RESOLVE_HOST (6) – 無法解析主機。 指定的遠端主機無法解析。

CURLE_COULDNT_CONNECT (7) – 無法通過 connect() 連接配接至主機或代理伺服器。

CURLE_FTP_WEIRD_SERVER_REPLY (8) – 在連接配接到 FTP 伺服器後,libcurl 需要收到特定的回複。 此錯誤代碼表示收到了不正常或不正确的回複。 指定的遠端伺服器可能不是正确的 FTP 伺服器。

CURLE_REMOTE_ACCESS_DENIED (9) – 我們無法通路網址中指定的資源。 對于 FTP,如果嘗試更改為遠端目錄,就會發生這種情況。

CURLE_FTP_WEIRD_PASS_REPLY (11) – 在将 FTP 密碼發送到伺服器後,libcurl 需要收到正确的回複。 此錯誤代碼表示傳回的是意外的代碼。

CURLE_FTP_WEIRD_PASV_REPLY (13) – libcurl 無法從伺服器端收到有用的結果,作為對 PASV 或 EPSV 指令的響應。 伺服器有問題。

CURLE_FTP_WEIRD_227_FORMAT (14) – FTP 伺服器傳回 227 行作為對 PASV 指令的響應。如果 libcurl 無法解析此行,就會傳回此代碼。

CURLE_FTP_CANT_GET_HOST (15) – 在查找用于新連接配接的主機時出現内部錯誤。

CURLE_FTP_COULDNT_SET_TYPE (17) – 在嘗試将傳輸模式設定為二進制或 ascii 時發生錯誤。

CURLE_PARTIAL_FILE (18) – 檔案傳輸尺寸小于或大于預期。當伺服器先報告了一個預期的傳輸尺寸,然後所傳送的資料與先前指定尺寸不相符時,就會發生此錯誤。

CURLE_FTP_COULDNT_RETR_FILE (19) – ‘RETR’ 指令收到了不正常的回複,或完成的傳輸尺寸為零位元組。

CURLE_QUOTE_ERROR (21) – 在向遠端伺服器發送自定義 “QUOTE” 指令時,其中一個指令傳回的錯誤代碼為 400 或更大的數字(對于 FTP),或以其他方式表明指令無法成功完成。

CURLE_HTTP_RETURNED_ERROR (22) – 如 果 CURLOPT_FAILONERROR 設定為 TRUE,且 HTTP 伺服器傳回 >= 400 的錯誤代碼,就會傳回此代碼。 (此錯 誤代碼以前又稱為 CURLE_HTTP_NOT_FOUND。)

CURLE_WRITE_ERROR (23) – 在向本地檔案寫入所收到的資料時發生錯誤,或由寫入回調 (write callback) 向 libcurl 傳回了一個錯誤。

CURLE_UPLOAD_FAILED (25) – 無法開始上傳。 對于 FTP,伺服器通常會拒絕執行 STOR 指令。錯誤緩沖區通常會提供伺服器對此問題的說明。 (此錯誤代碼以前又稱為 CURLE_FTP_COULDNT_STOR_FILE。)

CURLE_READ_ERROR (26) – 讀取本地檔案時遇到問題,或由讀取回調 (read callback) 傳回了一個錯誤。

CURLE_OUT_OF_MEMORY (27) – 記憶體配置設定請求失敗。此錯誤比較嚴重,若發生此錯誤,則表明出現了非常嚴重的問題。

CURLE_OPERATION_TIMEDOUT (28) – 操 作逾時。 已達到根據相應情況指定的逾時時間。 請注意: 自 Urchin 6.6.0.2 開始,逾時時間可以自行更改。 要指定遠端日志下載下傳逾時, 請打開 urchin.conf 檔案,取消以下行的注釋标記:

#DownloadTimeout: 30 

CURLE_FTP_PORT_FAILED (30) – FTP PORT 指令傳回錯誤。 在沒有為 libcurl 指定适當的位址使用時,最有可能發生此問題。 請參閱 CURLOPT_FTPPORT。

CURLE_FTP_COULDNT_USE_REST (31) – FTP REST 指令傳回錯誤。如果伺服器正常,則應當不會發生這種情況。

CURLE_RANGE_ERROR (33) – 伺服器不支援或不接受範圍請求。

CURLE_HTTP_POST_ERROR (34) – 此問題比較少見,主要由内部混亂引發。

CURLE_SSL_CONNECT_ERROR (35) – 同時使用 SSL/TLS 時可能會發生此錯誤。您可以通路錯誤緩沖區檢視相應資訊,其中會對此問題進行更詳細的介紹。可能是證書(檔案格式、路徑、許可)、密碼及其他因素導緻了此問題。

CURLE_FTP_BAD_DOWNLOAD_RESUME (36) – 嘗試恢複超過檔案大小限制的 FTP 連接配接。

CURLE_FILE_COULDNT_READ_FILE (37) – 無法打開 FILE:// 路徑下的檔案。原因很可能是檔案路徑無法識别現有檔案。 建議您檢查檔案的通路權限。

CURLE_LDAP_CANNOT_BIND (38) – LDAP 無法綁定。LDAP 綁定操作失敗。

CURLE_LDAP_SEARCH_FAILED (39) – LDAP 搜尋無法進行。

CURLE_FUNCTION_NOT_FOUND (41) – 找不到函數。 找不到必要的 zlib 函數。

CURLE_ABORTED_BY_CALLBACK (42) – 由回調中止。 回調向 libcurl 傳回了 “abort”。

CURLE_BAD_FUNCTION_ARGUMENT (43) – 内部錯誤。 使用了不正确的參數調用函數。

CURLE_INTERFACE_FAILED (45) – 界 面錯誤。 指定的外部界面無法使用。 請通過 CURLOPT_INTERFACE 設定要使用哪個界面來處理外部連接配接的來源 IP 位址。 (此錯誤代 碼以前又稱為 CURLE_HTTP_PORT_FAILED。)

CURLE_TOO_MANY_REDIRECTS (47) – 重定向過多。 進行重定向時,libcurl 達到了網頁點選上限。請使用 CURLOPT_MAXREDIRS 設定上限。

CURLE_UNKNOWN_TELNET_OPTION (48) – 無法識别以 CURLOPT_TELNETOPTIONS 設定的選項。 請參閱相關文檔。

CURLE_TELNET_OPTION_SYNTAX (49) – telnet 選項字元串的格式不正确。

CURLE_PEER_FAILED_VERIFICATION (51) – 遠端伺服器的 SSL 證書或 SSH md5 指紋不正确。

CURLE_GOT_NOTHING (52) – 伺服器未傳回任何資料,在相應情況下,未傳回任何資料就屬于出現錯誤。

CURLE_SSL_ENGINE_NOTFOUND (53) – 找不到指定的加密引擎。

CURLE_SSL_ENGINE_SETFAILED (54) – 無法将標明的 SSL 加密引擎設為預設選項。

CURLE_SEND_ERROR (55) – 無法發送網絡資料。

CURLE_RECV_ERROR (56) – 接收網絡資料失敗。

CURLE_SSL_CERTPROBLEM (58) – 本地用戶端證書有問題

CURLE_SSL_CIPHER (59) – 無法使用指定的密鑰

CURLE_SSL_CACERT (60) – 無法使用已知的 CA 證書驗證對等證書

CURLE_BAD_CONTENT_ENCODING (61) – 無法識别傳輸編碼

CURLE_LDAP_INVALID_URL (62) – LDAP 網址無效

CURLE_FILESIZE_EXCEEDED (63) – 超過了檔案大小上限

CURLE_USE_SSL_FAILED (64) – 請求的 FTP SSL 級别失敗

CURLE_SEND_FAIL_REWIND (65) – 進行發送操作時,curl 必須回轉資料以便重新傳輸,但回轉操作未能成功

CURLE_SSL_ENGINE_INITFAILED (66) – SSL 引擎初始化失敗

CURLE_LOGIN_DENIED (67) – 遠端伺服器拒絕 curl 登入(7.13.1 新增功能)

CURLE_TFTP_NOTFOUND (68) – 在 TFTP 伺服器上找不到檔案

CURLE_TFTP_PERM (69) – 在 TFTP 伺服器上遇到權限問題

CURLE_REMOTE_DISK_FULL (70) – 伺服器磁盤空間不足

CURLE_TFTP_ILLEGAL (71) – TFTP 操作非法

CURLE_TFTP_UNKNOWNID (72) – TFTP 傳輸 ID 未知

CURLE_REMOTE_FILE_EXISTS (73) – 檔案已存在,無法覆寫

CURLE_TFTP_NOSUCHUSER (74) – 運作正常的 TFTP 伺服器不會傳回此錯誤

CURLE_CONV_FAILED (75) – 字元轉換失敗

CURLE_CONV_REQD (76) – 調用方必須注冊轉換回調

CURLE_SSL_CACERT_BADFILE (77) – 讀取 SSL CA 證書時遇到問題(可能是路徑錯誤或通路權限問題)

CURLE_REMOTE_FILE_NOT_FOUND (78) – 網址中引用的資源不存在

CURLE_SSH (79) – SSH 會話中發生無法識别的錯誤

CURLE_SSL_SHUTDOWN_FAILED (80) – 無法終止 SSL 連接配接

---------------------

作者:byxdaz

來源:CSDN

原文:https://blog.csdn.net/byxdaz/article/details/81869881

版權聲明:本文為部落客原創文章,轉載請附上博文連結!