1. 程式人生 > >C/C++中libcurl的使用-Http GET方法使用詳解

C/C++中libcurl的使用-Http GET方法使用詳解

//getDataByCurl.cpp
#include <iostream>
#include <string>

#include <curl/curl.h>
#include <curl/types.h>;
#include <curl/easy.h>

#include <stdlib.h>
#include <string.h>
using namespace std;

struct MemoryStruct 
{
    char *memory;
    size_t size;
    MemoryStruct()
    {
        memory = (char *)malloc(1);
        size = 0;
    }
    ~MemoryStruct()
    {
        free(memory);
        memory = NULL;
        size = 0;
    }
};

size_t WriteMemoryCallback(void *ptr, size_t size, size_t nmemb, void *data)
{
    size_t realsize = size * nmemb;
    struct MemoryStruct *mem = (struct MemoryStruct *)data;

    mem->memory = (char *)realloc(mem->memory, mem->size + realsize + 1);
    if (mem->memory) 
    {
        memcpy(&(mem->memory[mem->size]), ptr, realsize);
        mem->size += realsize;
        mem->memory[mem->size] = 0;
    }
    return realsize;
}

int main()
{
    CURLcode res = curl_global_init(CURL_GLOBAL_ALL);
    if(CURLE_OK != res)
    {
        cout<<"curl init failed"<<endl;
        return 1;
    }

    CURL *pCurl = NULL;
    pCurl = curl_easy_init();

    if( NULL == pCurl)
    {
        cout<<"Init CURL failed..."<<endl;
        return -1;
    }

    string url = "http://xx.xx.xx.xx:50070/dfshealth.html"; //待請求的頁面
    string filename = "dfshealth.html"; //正確響應後,請請求轉寫成本地檔案的檔名即路徑,此處表示當前目錄下

    curl_easy_setopt(pCurl, CURLOPT_TIMEOUT, 3L);//請求超時時長
    curl_easy_setopt(pCurl, CURLOPT_CONNECTTIMEOUT, 10L); //連線超時時長 
    curl_easy_setopt(pCurl, CURLOPT_FOLLOWLOCATION, 1L);//允許重定向
    curl_easy_setopt(pCurl, CURLOPT_HEADER, 0L);  //若啟用,會將標頭檔案的資訊作為資料流輸出
    curl_easy_setopt(pCurl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);  //得到請求結果後的回撥函式

    MemoryStruct oDataChunk;  //請求結果的儲存格式
    curl_easy_setopt(pCurl, CURLOPT_WRITEDATA, &oDataChunk);

    curl_easy_setopt(pCurl, CURLOPT_NOSIGNAL, 1L); //關閉中斷訊號響應
    curl_easy_setopt(pCurl, CURLOPT_VERBOSE, 1L); //啟用時會彙報所有的資訊
    curl_easy_setopt(pCurl, CURLOPT_URL, url.c_str() ); //需要獲取的URL地址

    curl_slist *pList = NULL;
    pList = curl_slist_append(pList,"Accept-Encoding:gzip, deflate, sdch"); 
    pList = curl_slist_append(pList,"Accept-Language:zh-CN,zh;q=0.8"); 
    pList = curl_slist_append(pList,"Connection:keep-alive");
    curl_easy_setopt(pCurl, CURLOPT_HTTPHEADER, pList); 

    res = curl_easy_perform(pCurl);  //執行請求

    long res_code=0;
    res=curl_easy_getinfo(pCurl, CURLINFO_RESPONSE_CODE, &res_code);

    //正確響應後,請請求轉寫成本地檔案的檔案
    if(( res == CURLE_OK ) && (res_code == 200 || res_code == 201))
    {
        FILE* fTmpMem = (FILE*)oDataChunk.memory;
        if (!fTmpMem) {

        }

        FILE *fp=fopen(filename.c_str(),"wb");
        if(!fp)
        {   
            cout<<"open file failed";
            return -1;
        }   

        fwrite(fTmpMem, 1, oDataChunk.size, fp);
        fclose(fp);
        return true;
    }
    curl_slist_free_all(pList); 
    curl_easy_cleanup(pCurl);
    curl_global_cleanup();

    return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
編譯,執行:

# g++ -g getDataByCurl.cpp -o run -lcurl
# ./run
* About to connect() to xx.xx.xx.xx port 50070 (#0)
*   Trying xx.xx.xx.xx... * connected
* Connected to xx.xx.xx.xx (xx.xx.xx.xx) port 50070 (#0)
> GET /dfshealth.html HTTP/1.1
Host: xx.xx.xx.xx:50070
Accept: */*
Accept-Encoding:gzip, deflate, sdch
Accept-Language:zh-CN,zh;q=0.8
Connection:keep-alive

< HTTP/1.1 200 OK
< Cache-Control: no-cache
< Expires: Tue, 17 Oct 2017 02:49:59 GMT
< Date: Tue, 17 Oct 2017 02:49:59 GMT
< Pragma: no-cache
< Expires: Tue, 17 Oct 2017 02:49:59 GMT
< Date: Tue, 17 Oct 2017 02:49:59 GMT
< Pragma: no-cache
< Content-Type: text/html; charset=utf-8
< Accept-Ranges: bytes
< Content-Length: 13320
< Last-Modified: Thu, 18 Aug 2016 01:49:57 GMT
< Server: Jetty(6.1.26)

* Connection #0 to host xx.xx.xx.xx left intact
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
程式執行完後,會在當前目錄下生成名為dfshealth.html的檔案,該檔案內容即為配置的url地址的頁面。 
在上述程式碼中,程式試圖獲取整個網頁的結果,如果客戶端是多執行緒的,務必將CURLOPT_NOSIGNAL置為1。結構體MemoryStruct是自定義的資料結構,用於儲存CURL執行的結果,CURLOPT_WRITEDATA將該物件傳遞給回撥函式,在回撥函式WriteMemoryCallback中,將返回結果分配儲存空間,並拷貝返回記憶體到MemoryStruct物件中。通過curl_easy_getinfo獲取curl執行結果的會話資訊,將判斷執行成功時,客戶端將MemoryStruct物件的內容寫到指定檔案中。

相關介面及引數說明:

CURL_EXTERN CURLcode curl_global_init(long flags);
1
該函式用於操作前的全域性初始化,它是非執行緒安全的,它應該在所有其他libcurl函式呼叫之前被呼叫,而且只能被呼叫一次。如果使用者沒有呼叫該函式,那麼在後續呼叫curl_easy_init()進行初始化時,會自動呼叫curl_global_init(CURL_GLOBAL_DEFAULT),以確保初始化了”global SSL stuff”,參見lib/easy.c原始碼。 
引數: 
CURL_GLOBAL_ALL   初始化除CURL_GLOBAL_ACK_EINTR外的所有系統。 
CURL_GLOBAL_SSL   初始化SSL 
CURL_GLOBAL_WIN32   初始化Win32 socket libraries. 
CURL_GLOBAL_NOTHING   不初始化任何系統 
CURL_GLOBAL_DEFAULT   等同於CURL_GLOBAL_ALL 
CURL_GLOBAL_ACK_EINTR   設定了這個標籤後,當curl在連線或等待資料請求時,curl將接收EINTR條件,否則,curl會一直等待。 
返回值: 
正常通過時返回0,非零值表示出現錯誤。

CURL_EXTERN void curl_global_cleanup(void);
1
該函式用於進行全域性的清理工作,對於使用libcurl的每一個應用,應該只被呼叫一次。

CURL_EXTERN CURL *curl_easy_init(void);
1
外部介面,用於建立,分配並返回一個初始化的CURL控制代碼,作為其他curl_easy函式的作用物件。

CURL_EXTERN CURLcode curl_easy_setopt(CURL *curl, CURLoption option, ...);
CURLcode curl_easy_setopt(CURL *handle, CURLOPT_TIMEOUT, long timeout);
CURLcode curl_easy_setopt(CURL *handle, CURLOPT_TIMEOUT_MS, long timeout);
1
2
3
外部介面,用於配置CURL物件的選項引數。上述程式碼中涉及的一些引數選項: 
CURLOPT_TIMEOUT:一個完整的請求的超時時長,前者時間單位為秒,後者為毫秒。如果CURLOPT_TIMEOUT和CURLOPT_TIMEOUT_MS都設定了,那麼後面的設定將會覆蓋前面的設定。

CURLcode curl_easy_setopt(CURL *handle, CURLOPT_CONNECTTIMEOUT, long timeout);
CURLcode curl_easy_setopt(CURL *handle, CURLOPT_CONNECTTIMEOUT_MS, long timeout);
1
2
CURLOPT_CONNECTTIMEOUT:配置在建立請求的連結階段的超時時長限制,關於時長的引數與上面的TIMEOUT類似。

CURLcode curl_easy_setopt(CURL *handle, CURLOPT_FOLLOWLOCATION, long enable);
CURLOPT_FOLLOWLOCATION:使用enable引數控制是否允許URL地址的重定向,關於地址的重定向請參見其他資料。

CURLcode curl_easy_setopt(CURL *handle, CURLOPT_HEADER, long onoff);
CURLOPT_HEADER:當onoff被設定為1時,即告訴libcurl在輸出請求體時包含頭部資訊。

CURLcode curl_easy_setopt(CURL *handle, CURLOPT_WRITEFUNCTION, write_callback);
CURLOPT_WRITEFUNCTION:傳遞呼叫完成時的回撥函式,回撥函式的原型為:
size_t write_callback(char *ptr, size_t size, size_t nmemb, void *userdata);

CURLcode curl_easy_setopt(CURL *handle, CURLOPT_WRITEDATA, void *pointer);
CURLOPT_WRITEDATA:一個自定義的指標pointer,用於傳遞給上面的write_callback

CURLcode curl_easy_setopt(CURL *handle, CURLOPT_NOSIGNAL, long onoff);
CURLOPT_NOSIGNAL:如果是多執行緒,請將該引數置為1。這個選項用於unix環境下的多執行緒應用仍然可以使用各種timeout選項,而不會引發訊號中斷致使程式退出。

CURLcode curl_easy_setopt(CURL *handle, CURLOPT_VERBOSE, long onoff);
CURLOPT_VERBOSE:如果將onoff置為1,那麼將使得呼叫過程中輸出更多的關於呼叫操作的詳細資訊。

CURLcode curl_easy_setopt(CURL *handle, CURLOPT_URL, char *URL);
CURLOPT_URL:請求的url地址

curl_easy_setopt(pCurl, CURLOPT_HTTPHEADER, pList); 
CURLOPT_HTTPHEADER:設定HTTP請求的頭資訊
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
更多其他引數詳見原始碼”docs/libcurl/opts”

CURL_EXTERN struct curl_slist *curl_slist_append(struct curl_slist *,const char *);
向curl_slist連結串列中追加引數,curl_slist_append()函式是很有用的,因為如果你什麼都不寫,CUrl會傳輸一個類似"Get /你的網頁 accept:*/*"之類的簡單協議,在某些驗證較為嚴格的伺服器,這樣的Http連結協議字會被丟棄的。 curl_slist_append()這個API可以讓你偽裝成一個標準的網頁瀏覽器的請求。關於相關的請求引數,可以通過瀏覽器的開發者中工具中預先檢視。

CURL_EXTERN void curl_slist_free_all(struct curl_slist *);
用於釋放之前curl_slist中資料

CURL_EXTERN CURLcode curl_easy_perform(CURL *curl);
外部介面,用於執行CURL物件,是一個阻塞型別的操作

CURL_EXTERN CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ...);
從curl執行結果中獲取內部資訊。該函式的第三個引數必須是一個指向long,char或者double型別的指標,當函式執行結果返回CURLE_OK時,該指標的結果將會根據實際情況被填充響應的結果。

CURL_EXTERN void curl_easy_cleanup(CURL *curl);
呼叫該函式來結束一個curl easy會話。關閉一個由curl_easy_init()生成的handle
--------------------- 
作者:cjf_wei 
來源:CSDN 
原文:https://blog.csdn.net/cjf_wei/article/details/79118415 
版權宣告:本文為博主原創文章,轉載請