• 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.
    ")
    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重试机制。在实现中看一下细节!

    //
    // 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;
    }
    

      

    测试代码:

    #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 注意事项
     

     1、解决线程安全及避免core错误问题方式

      1) curl_global_init()在多线程环境下,是线程不安全的。所以在多线程环境下,要在主线程中调用这个方法。配套的,在主线程中调用curl_global_cleanup()方法。

      2)curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1L); 控制域名解析的超时,其需要一个sigjmp_buf型的全局变量,多线程时会修改它。

      3)  curl_easy_setopt(curl, CURLOPT_FORBID_REUSE, 1);默认情况下libcurl完成一个任务以后,出于重用连接的考虑不会马上关闭。如果没有新的TCP请求来重用这个连接,那么只能等到CLOSE_WAIT超时,这个时间默认在7200秒甚至更高,太多的CLOSE_WAIT连接会导致性能问题

     2、要想让curl_easy_perform(),能够执行,必须得有个配套方法curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, req_reply);

     
     
    推荐
  • 相关阅读:
    uni-app实现下拉效果
    求点到已知直线的距离和点到直线的垂点坐标
    Mybatis 自定义SqlSessionFactoryBean扫描通配符typeAliasesPackage
    前端string类型的日期 -后端实体类属性为Date
    如何更新npm为最新版本
    简述ThreadPoolExecutor的运行机制
    list在遍历过程中的add/remove
    Linux下安装mysql
    Linux下安装activeMQ并设置开机启动
    solr集群环境搭建
  • 原文地址:https://www.cnblogs.com/baochuan/p/9141712.html
Copyright © 2020-2023  润新知