[Ubuntu] 编译&使用 curl 库进行简单网络请求
当使用C++做HTTP客户端时,目前通用的做法就是使用libcurl。其官方网站的地址是 http://curl.haxx.se/,该网站主要提供了Curl和libcurl。Curl是命令行工具,用于完成FTP, FTPS, HTTP, HTTPS, GOPHER, TELNET, DICT, FILE 以及 LDAP的命令的请求及接收回馈。libcurl提供给开发者,用于使用C++跨平台的开发各种网络协议的请求及响应。里面的文档非常齐全,不过都是英文的。
0、系统环境:
Ubuntu 14.04
curl v7.46.0
1、编译 libcurl 库:
1)下载 curl 源码:
1 | git clone https://github.com/bagder/curl.git |
或者使用我网盘里面的代码:
http://pan.baidu.com/s/1dDMNrKt
2)检查 curl 依赖项是否安装:
1 | sudo apt-get build-dep curl |
3)编译安装:
依次运行以下命令进行编译安装(需要输入管理员密码):
1 2 3 4 | ./buildconf ./configure make sudo make install |
其中我们需要的库文件自动安装在:
/usr/local/include
/usr/local/lib
两个文件夹下面。
2、封装 CHttpClient 类进行网络请求:
为了方便使用,我们这里采用了一个封装的 CHttpClient 类,这个类只包含同步 HTTP/HTTPS 的 GET、POST 请求。该封装部分代码来自:
http://www.tamabc.com/article/245027.html
它的源代码如下:
头文件 CHttpClient.hpp:
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 | #ifndef __HTTP_CURL_H__ #define __HTTP_CURL_H__ #include <string> class CHttpClient { public: CHttpClient(void); ~CHttpClient(void); public: /** * @brief HTTP POST請求 * @param strUrl 輸入參數,請求的Url地址,如:http://www.baidu.com * @param strPost 輸入參數,使用如下格式para1=val1¶2=val2&… * @param strResponse 輸出參數,返回的內容 * @return 返回是否Post成功 */ int Post(const std::string & strUrl, const std::string & strPost, std::string & strResponse); /** * @brief HTTP GET請求 * @param strUrl 輸入參數,請求的Url地址,如:http://www.baidu.com * @param strResponse 輸出參數,返回的內容 * @return 返回是否Post成功 */ int Get(const std::string & strUrl, std::string & strResponse); /** * @brief HTTPS POST請求,無證書版本 * @param strUrl 輸入參數,請求的Url地址,如:https://www.alipay.com * @param strPost 輸入參數,使用如下格式para1=val1¶2=val2&… * @param strResponse 輸出參數,返回的內容 * @param pCaPath 輸入參數,爲CA證書的路徑.如果輸入爲NULL,則不驗證服務器端證書的有效性. * @return 返回是否Post成功 */ int Posts(const std::string & strUrl, const std::string & strPost, std::string & strResponse, const char * pCaPath = NULL); /** * @brief HTTPS GET請求,無證書版本 * @param strUrl 輸入參數,請求的Url地址,如:https://www.alipay.com * @param strResponse 輸出參數,返回的內容 * @param pCaPath 輸入參數,爲CA證書的路徑.如果輸入爲NULL,則不驗證服務器端證書的有效性. * @return 返回是否Post成功 */ int Gets(const std::string & strUrl, std::string & strResponse, const char * pCaPath = NULL); /** * @brief HTTPS GET請求,無證書版本 * @param strUrl 輸入參數,請求的Url地址,如:https://www.alipay.com * @param strFilePath 输入參數,文件保存的路径 * @return 返回是否下载成功 */ int Download(const std::string & strUrl, std::string & strFilePath); public: void SetDebug(bool bDebug); private: bool m_bDebug; }; #endif |
源文件 CHttpClient.cpp:
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 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 | #include "CHttpClient.hpp" #include "curl/curl.h" #include <string> CHttpClient::CHttpClient(void) : m_bDebug(false) { } CHttpClient::~CHttpClient(void) { } static int OnDebug(CURL *, curl_infotype itype, char * pData, size_t size, void *) { if(itype == CURLINFO_TEXT) { //printf("[TEXT]%s\n", pData); } else if(itype == CURLINFO_HEADER_IN) { printf("[HEADER_IN]%s\n", pData); } else if(itype == CURLINFO_HEADER_OUT) { printf("[HEADER_OUT]%s\n", pData); } else if(itype == CURLINFO_DATA_IN) { printf("[DATA_IN]%s\n", pData); } else if(itype == CURLINFO_DATA_OUT) { printf("[DATA_OUT]%s\n", pData); } return 0; } static size_t OnWriteData(void* buffer, size_t size, size_t nmemb, void* lpVoid) { std::string* str = dynamic_cast<std::string*>((std::string *)lpVoid); if( NULL == str || NULL == buffer ) { return -1; } char* pData = (char*)buffer; str->append(pData, size * nmemb); return nmemb; } static size_t OnWriteFile(void *ptr, size_t size, size_t nmemb, FILE *stream) { size_t written; written = fwrite(ptr, size, nmemb, stream); return written; } int CHttpClient::Post(const std::string & strUrl, const std::string & strPost, std::string & strResponse) { CURLcode res; CURL* curl = curl_easy_init(); if(NULL == curl) { return CURLE_FAILED_INIT; } if(m_bDebug) { curl_easy_setopt(curl, CURLOPT_VERBOSE, 1); curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, OnDebug); } curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str()); curl_easy_setopt(curl, CURLOPT_POST, 1); curl_easy_setopt(curl, CURLOPT_POSTFIELDS, strPost.c_str()); curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, OnWriteData); curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&strResponse); curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 3); curl_easy_setopt(curl, CURLOPT_TIMEOUT, 3); res = curl_easy_perform(curl); curl_easy_cleanup(curl); return res; } int CHttpClient::Get(const std::string & strUrl, std::string & strResponse) { CURLcode res; CURL* curl = curl_easy_init(); if(NULL == curl) { return CURLE_FAILED_INIT; } if(m_bDebug) { curl_easy_setopt(curl, CURLOPT_VERBOSE, 1); curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, OnDebug); } curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str()); curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, OnWriteData); curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&strResponse); /** * 當多個線程都使用超時處理的時候,同時主線程中有sleep或是wait等操作。 * 如果不設置這個選項,libcurl將會發信號打斷這個wait從而導致程序退出。 */ curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 3); curl_easy_setopt(curl, CURLOPT_TIMEOUT, 3); res = curl_easy_perform(curl); curl_easy_cleanup(curl); return res; } int CHttpClient::Download(const std::string & strUrl, std::string & strFilePath) { CURLcode res; CURL* curl = curl_easy_init(); if(NULL == curl) { return CURLE_FAILED_INIT; } if(m_bDebug) { curl_easy_setopt(curl, CURLOPT_VERBOSE, 1); curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, OnDebug); } FILE *fp; fp = fopen(strFilePath.c_str(),"wb"); curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str()); //curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, OnWriteFile); curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp); /** * 當多個線程都使用超時處理的時候,同時主線程中有sleep或是wait等操作。 * 如果不設置這個選項,libcurl將會發信號打斷這個wait從而導致程序退出。 */ curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 3); curl_easy_setopt(curl, CURLOPT_TIMEOUT, 3); res = curl_easy_perform(curl); curl_easy_cleanup(curl); fclose(fp); return res; } |
3、调用示例:
1)示例1:调用 Get 方法
源代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | #include "CHttpClient.hpp" #include <fstream> #include <iostream> using namespace std; int main (int argc, char** argv) { // 同步网络 CHttpClient net; string htmlStr; net.Get("http://www.baidu.com/", htmlStr); cout<<htmlStr<<endl; return 0; } |
这个示例非常简单,就是获取一个网址的内容,使用Get方法,就不解释了。
另外它还有Post方法和HTTPS的相关方法,可以自行研究下。
2)示例2:调用 Download 方法
源代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | #include <iostream> #include "CHttpClient.hpp" using namespace std; int main(int argc, const char * argv[]) { CHttpClient net; string url = "http://www.libsdl.org/projects/SDL_image/docs/demos/lena.jpg"; string path = "./lena.jpg"; net.Download(url, path); return 0; } |
这个示例调用 Download 函数从网络上下载一张 lena 图片并保存到本地。