CLion之C++框架篇-優化開源框架,引入curl,實現get方式獲取資源(四)

 
背景
 
  結合上一篇 CLion之C++框架篇-優化框架,引入boost(三),繼續進行框架優化!在項目中,咱們常常會經過get方式拉取第三方資源,這一版優化引入類庫curl,用來拉取第三方資源庫。
 
  開源框架代碼:https://github.com/rtxbc/cplus/tree/master/work
 
配置使用
 
  
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());
}

  

 

CURL 注意事項
 

 一、解決線程安全及避免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

 
 
推薦
相關文章
相關標籤/搜索