cmake_minimum_required(VERSION 3.11.2)
project(work)
message(STATUS "start load boost ========================================")
# BOOST
## 設(shè)置個(gè)變量控制
SET(BOOST_MIN_VERSION "1.67.0")
## 動(dòng)態(tài)查找
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,會(huì)在當(dāng)前目錄生成libtest.a靜態(tài)庫
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/)
#編譯器相關(guān)設(shè)置
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") # 調(diào)試信息
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重試機(jī)制。在實(shí)現(xiàn)中看一下細(xì)節(jié)!

//
// 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); // 傳輸超時(shí)
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 0); // 連接超時(shí)
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1L);
curl_easy_setopt(curl, CURLOPT_FORBID_REUSE, 1);
CURLcode res = curl_easy_perform(curl); // 執(zhí)行
// 重試
while (res != CURLE_OK && --retries > 0) {
res = curl_easy_perform(curl); // 執(zhí)行
}
curl_easy_cleanup(curl);
}
curl_slist_free_all(headers);
return response;
}
測試代碼:

#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());
}
1、解決線程安全及避免core錯(cuò)誤問題方式
1) curl_global_init()在多線程環(huán)境下,是線程不安全的。所以在多線程環(huán)境下,要在主線程中調(diào)用這個(gè)方法。配套的,在主線程中調(diào)用curl_global_cleanup()方法。
2)curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1L); 控制域名解析的超時(shí),其需要一個(gè)sigjmp_buf型的全局變量,多線程時(shí)會(huì)修改它。
3) curl_easy_setopt(curl, CURLOPT_FORBID_REUSE, 1);默認(rèn)情況下libcurl完成一個(gè)任務(wù)以后,出于重用連接的考慮不會(huì)馬上關(guān)閉。如果沒有新的TCP請(qǐng)求來重用這個(gè)連接,那么只能等到CLOSE_WAIT超時(shí),這個(gè)時(shí)間默認(rèn)在7200秒甚至更高,太多的CLOSE_WAIT連接會(huì)導(dǎo)致性能問題
2、要想讓curl_easy_perform(),能夠執(zhí)行,必須得有個(gè)配套方法curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, req_reply);

浙公網(wǎng)安備 33010602011771號(hào)