这两天简单研究了下CURL访问网站读取数据的方式,做了简单的实验,思路很简单,就是提供一个URL,然后从URL返回的数据读取出来,显示到控制台,或者存储到文件中。具体的描述以及注意事项,代码的注释中都有写明。
上代码。
// DemoLibcurl.cpp : Defines the entry point for the console application. // #include "stdafx.h" #define CURL_STATICLIB // 由于我使用的是CURL静态链接,所以需要定义上这个宏 #include "http://www.cnblogs.com/../include/curl/curl.h" // 一下三个lib为libcurl.lib所依赖的三个库 #pragma comment(lib, "Wldap32.lib") #pragma comment(lib, "Ws2_32.lib") #pragma comment(lib, "Advapi32.lib") #ifdef _DEBUG #pragma comment(lib,"http://www.cnblogs.com/../lib/libcurld.lib") #else #pragma comment(lib,"http://www.cnblogs.com/../lib/libcurl.lib") #endif #include <iostream> #include <string> using namespace std; // 定义一个break宏 #define BREAK_ON_NOT_EQUAL(compareValue, resultValue) {if((compareValue) != (resultValue))break;} // 执行输出到标准输出流 bool PerformToStdout(IN CURL* nphEasycurl); // curl指定格式的回调函数 size_t WriteToString(void *buffer, size_t size, size_t nmemb, void *userp); size_t WriteToFile(void *buffer, size_t size, size_t nmemb, void *userp); // 执行输出到字符串 bool PerformToString(IN CURL* nphEasycurl, IN string& rstrBuffer); // 执行输出到文件 bool PerformToFile(IN CURL* nphEasycurl, IN char* nscFileName, bool nbIsUseCallBackMethod = false); int _tmain(int argc, _TCHAR* argv[]) { // 进行初始化 CURL* lphEasycurl = curl_easy_init(); do { // 初始化失败 if(NULL == lphEasycurl) { cout << "Error: Init curl handle failed." << endl; break; } // 获取当前使用的curl库的版本信息 curl_version_info_data* ldVersionInfo = curl_version_info(CURLVERSION_NOW); if(NULL != ldVersionInfo && ldVersionInfo->age > 0) { //// 判断是否支持所需要的功能 //if(1 != (ldVersionInfo->features & CURL_VERSION_GSSNEGOTIATE)) // 不明白这里要用那个宏去进行判断才表示支持HTTP //{ // cout << "Error: Current Curl version do`nt support HTTP." << endl; // break; //} } else // 获取版本信息失败 { cout << "Error: Get version info of Curl failed." << endl; break; } // 设置接受错误信息的缓存,CURL_ERROR_SIZE为curl要求的最小大小 char lscErrBuffer[CURL_ERROR_SIZE]; curl_easy_setopt(lphEasycurl, CURLOPT_ERRORBUFFER, &lscErrBuffer); // 接受错误描述 // 设置URL curl_easy_setopt(lphEasycurl, CURLOPT_URL, "http://www.cnn.com/"); // 执行 int liOutputType = 2; // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~通过更改这个值,来尝试不同的方式 bool lbIsPerformSuccess = false; string lstrDataBuffer; switch(liOutputType) { case 1: // 输出到字符串 { lbIsPerformSuccess = PerformToString(lphEasycurl, lstrDataBuffer); } break; case 2: // 输出到文件 { lbIsPerformSuccess = PerformToFile(lphEasycurl, "output.txt", true); // ~~~~~~~~~更改第三个参数来调用不同的实现方式 } break; default: // 输出到标准输出 { lbIsPerformSuccess = PerformToStdout(lphEasycurl); } break; } // 执行失败,输出错误描述 if(false == lbIsPerformSuccess) { cout << "Error: " << lscErrBuffer << endl; break; } // 根据设置的类型进行输出 if(1 == liOutputType) { cout << "The data read from url:" << lstrDataBuffer.c_str() << endl; } else if(2 == liOutputType) { cout << "Success: The data have saved to output.txt" << endl; } } while (false); // 清空初始化数据 if(NULL != lphEasycurl) curl_easy_cleanup(lphEasycurl); cout<<endl<<"Press anykey to continue!"<<endl; getchar(); return 0; } bool PerformToStdout(IN CURL* nphEasycurl) { bool lbResult = false; do { if(CURLE_OK != curl_easy_perform(nphEasycurl)) break; lbResult = true; } while (false); return lbResult; } // 功能: // libcurl写数据所使用的标准回调函数格式 // 参数: // buffer所指向数据块的字节数为size * nmemb,注意不会以0结尾。 // userp是通过设置CURLOPT_WRITEDATA属性传进来的指针 // 返回值: // 通常作为实际处理的字节数,如果处理的总字节数和传入的字节总数不同,curl将中止操作并返回错误码CURLE_WRITE_ERROR size_t WriteToString(void *buffer, size_t size, size_t nmemb, void *userp) { *((std::string*)userp) += (char*)buffer; // 不是说不是以0结尾的吗?这里用这种方式不会访问越界么? return size * nmemb; } bool PerformToString(IN CURL* nphEasycurl, IN string& rstrBuffer) { bool lbResult = false; do { curl_easy_setopt(nphEasycurl, CURLOPT_WRITEFUNCTION, WriteToString); // 如果不提供这个回调函数,curl将会将数据输出到stdout中。 curl_easy_setopt(nphEasycurl, CURLOPT_WRITEDATA, &rstrBuffer); if(CURLE_OK != curl_easy_perform(nphEasycurl)) break; lbResult = true; } while (false); return lbResult; } // 同WriteToString size_t WriteToFile(void *buffer, size_t size, size_t nmemb, void *userp) { FILE* lphFile = (FILE*)userp; if(NULL != lphFile) { fwrite(buffer, size, nmemb, lphFile); } return size * nmemb; } bool PerformToFile(IN CURL* nphEasycurl, IN char* nscFileName, bool nbIsUseCallBackMethod) { bool lbResult = false; FILE* lphFile = NULL; // CURL要求必须使用FILE do { if(NULL == nscFileName) break; // 打开文件 lphFile = fopen(nscFileName, "wb+"); if(NULL == lphFile) { cout << "file open failed." << endl; break; } if(false != nbIsUseCallBackMethod) // 使用回调方式 { // 方式1,将File*传递给回调函数,自己进行处理。 BREAK_ON_NOT_EQUAL(CURLE_OK, curl_easy_setopt(nphEasycurl, CURLOPT_WRITEFUNCTION, WriteToFile)); } // 方式2,直接将FILE*传递给CURL去进行处理,!注意,CURL默认会使用fwrite写入数据,这也是为什么并且只能传入FILE*的原因。 BREAK_ON_NOT_EQUAL(CURLE_OK, curl_easy_setopt(nphEasycurl, CURLOPT_WRITEDATA, lphFile)); // 方式3,用PerformToFile,然后将返回的数据写入File中,这里不进行实验 // 执行 BREAK_ON_NOT_EQUAL(CURLE_OK, curl_easy_perform(nphEasycurl)); lbResult = true; } while (false); if(NULL != lphFile) fclose(lphFile); return lbResult; }