cmake_minimum_required(VERSION 3.11.2) project(work) message(STATUS "start load boost ========================================") # BOOST ## 設置個變量控制 SET(BOOST_MIN_VERSION "1.67.0") ## 動態查找 FIND_PACKAGE(Boost ${BOOST_MIN_VERSION} REQUIRED) if(NOT Boost_FOUND) message(FATAL_ERROR "Fatal error:Boost (version >=${BOOST_MIN_VERSION}) required.\n") endif() message(STATUS "Boost_INCLUDE_DIRS: ${Boost_INCLUDE_DIRS}") message(STATUS "Boost_LIBRARIES: ${BOOST_LIBRARY_DIRS}") message(STATUS "Boost_VERSION: ${Boost_VERSION}") ## 頭文件 INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIRS}) LINK_DIRECTORIES(${Boost_LIBRARY_DIRS}) # .BOOST message(STATUS "end load boost ========================================") # 編譯google test,會在當前目錄生成libtest.a靜態庫 add_subdirectory(lib/ext/googletest) #頭文件 INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/src/include ${PROJECT_SOURCE_DIR}lib/ext/googletest/include) #庫文件 : libtest.a 添加到連接路徑中 link_directories(${PROJECT_SOURCE_DIR}/lib ${PROJECT_SOURCE_DIR}/lib/ext/googletest /usr/local/opt/curl/lib/) #編譯器相關設置 set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/output/bin") set(LIBRARIES pthread) set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_COMPILER "clang++" ) # 顯示指定使用的C++編譯器 set(CMAKE_CXX_FLAGS "-g") # 調試信息 set(CMAKE_CXX_FLAGS "-Wall") # 開啓全部警告 set(CMAKE_CXX_FLAGS "-lboost_date_time-mt-d") # boost #源碼目錄 FILE(GLOB_RECURSE SOURCEFILES ${PROJECT_SOURCE_DIR}/src/utility/*.cpp) FILE(GLOB_RECURSE TEST_SOURCEFILES ${PROJECT_SOURCE_DIR}/src/test/*.cpp) add_custom_target(cmake-build-debug) add_executable(${PROJECT_NAME} ${PROJECT_SOURCE_DIR}/src/main/main.cpp ${SOURCEFILES}) add_executable(work_test ${TEST_SOURCEFILES} ${SOURCEFILES}) target_link_libraries(${PROJECT_NAME} gtest ${Boost_LIBRARIES} curl) target_link_libraries(work_test gtest ${Boost_LIBRARIES} curl)
// // Created by Zhou,Baochuan on 18/6/5. // #ifndef WORK_HTTP_H #define WORK_HTTP_H #include "common.h" #include <curl/curl.h> namespace work { class Http { public: Http(); ~Http(); static string get(string url, unsigned retries = 3); }; } #endif //WORK_HTTP_H
注意:get方法中增長了retries重試機制。在實現中看一下細節!html
// // Created by Zhou,Baochuan on 18/6/5. // #include "http.h" using namespace work; Http::Http() { curl_global_init(CURL_GLOBAL_NOTHING); } Http::~Http() { curl_global_cleanup(); } size_t req_reply(void* ptr, size_t size, size_t nmemb, void* stream) { //cout << "----->reply" << endl; std::string* str = (std::string*)stream; //cout << *str << endl; (*str).append((char*)ptr, size * nmemb); return size * nmemb; } string Http::get(string url, unsigned int retries) { string response; CURL *curl; struct curl_slist *headers = NULL; //headers = curl_slist_append(headers, "Accept: Agent-007"); curl = curl_easy_init() ; if (curl) { //curl_easy_setopt(curl, CURLOPT_PROXY, "10.99.60.201:8080");// 代理 curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, req_reply); curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*) &response); //curl_easy_setopt(curl, CURLOPT_VERBOSE, 1); curl_easy_setopt(curl, CURLOPT_TIMEOUT, 0); // 傳輸超時 curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 0); // 鏈接超時 curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1L); curl_easy_setopt(curl, CURLOPT_FORBID_REUSE, 1); CURLcode res = curl_easy_perform(curl); // 執行 // 重試 while (res != CURLE_OK && --retries > 0) { res = curl_easy_perform(curl); // 執行 } curl_easy_cleanup(curl); } curl_slist_free_all(headers); return response; }
測試代碼:git
#include "common.h" #include "http.h" #include <gtest/gtest.h> using namespace work; // curl版本要求 TEST(curl, all) { EXPECT_EQ(3, CURLVERSION_NOW); Http http; string url = "http://47.95.220.249/"; ASSERT_FALSE(http.get(url).empty()); }
一、解決線程安全及避免core錯誤問題方式github
1) curl_global_init()在多線程環境下,是線程不安全的。因此在多線程環境下,要在主線程中調用這個方法。配套的,在主線程中調用curl_global_cleanup()方法。安全
2)curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1L); 控制域名解析的超時,其須要一個sigjmp_buf型的全局變量,多線程時會修改它。bash
3) curl_easy_setopt(curl, CURLOPT_FORBID_REUSE, 1);默認狀況下libcurl完成一個任務之後,出於重用鏈接的考慮不會立刻關閉。若是沒有新的TCP請求來重用這個鏈接,那麼只能等到CLOSE_WAIT超時,這個時間默認在7200秒甚至更高,太多的CLOSE_WAIT鏈接會致使性能問題多線程
二、要想讓curl_easy_perform(),可以執行,必須得有個配套方法curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, req_reply);app