HTTP实现心跳模块

发布于:2025-04-14 ⋅ 阅读:(17) ⋅ 点赞:(0)

HTTP实现心跳模块

使用轻量级的c++HTTP库cpp-httplib重现实现HTTP心跳模块

头文件HttplibHeartbeat.h

#ifndef HTTPLIB_HEARTBEAT_H
#define HTTPLIB_HEARTBEAT_H

#include <string>
#include <thread>
#include <atomic>
#include <chrono>
#include <functional>
#include <memory>
#include "httplib.h"
#include "json.hpp"

using json = nlohmann::json;

class HttplibHeartbeat {
public:
    using ResponseCallback = std::function<void(const std::string& response, bool success)>;
    
    /**
     * @brief 构造函数
     * @param host 服务器主机名或IP
     * @param port 服务器端口
     * @param endpoint 心跳端点路径
     * @param interval 心跳间隔(秒)
     */
    HttplibHeartbeat(const std::string& host, int port, 
                    const std::string& endpoint, unsigned int interval);
    
    /** 
     * @param heartbeat_data 心跳数据(将转换为JSON)
     */
    HttplibHeartbeat(const std::string& host, int port, 
                 const std::string& endpoint, unsigned int interval,
                 const std::map<std::string, std::string>& heartbeat_data);
    
    ~HttplibHeartbeat();
    
    void start(ResponseCallback callback);
    void stop();
    void setInterval(unsigned int interval);
    bool isRunning() const;
    void updateHeartbeatData(const std::map<std::string, std::string>& new_data);

private:
    void heartbeatLoop();
    json createHeartbeatJson() const;
    
    std::string m_host;
    int m_port;
    std::string m_endpoint;
    unsigned int m_interval;
    std::atomic<bool> m_running;
    std::thread m_thread;
    ResponseCallback m_callback;
    std::unique_ptr<httplib::Client> m_client;
    std::map<std::string, std::string> m_heartbeat_data;
};

#endif // HTTPLIB_HEARTBEAT_H

cpp源文件 HttplibHeartbeat.cpp

#include "HttplibHeartbeat.h"
#include <iostream>

HttplibHeartbeat::HttplibHeartbeat(const std::string& host, int port, 
                                  const std::string& endpoint, unsigned int interval)
    : m_host(host), m_port(port), m_endpoint(endpoint), 
      m_interval(interval), m_running(false) {
    
    m_client = std::make_unique<httplib::Client>(host, port);
    // 设置超时时间
    m_client->set_connection_timeout(3); // 3秒连接超时
    m_client->set_read_timeout(5);       // 5秒读取超时
}

HttplibHeartbeat::HttplibHeartbeat(const std::string& host, int port, 
                           const std::string& endpoint, unsigned int interval,
                           const std::map<std::string, std::string>& heartbeat_data)
    : m_host(host), m_port(port), m_endpoint(endpoint), 
      m_interval(interval), m_running(false),
      m_heartbeat_data(heartbeat_data) {
    
    m_client = std::make_unique<httplib::Client>(host, port);
    m_client->set_connection_timeout(3);
    m_client->set_read_timeout(5);
}

HttplibHeartbeat::~HttplibHeartbeat() {
    stop();
}

void HttplibHeartbeat::start(ResponseCallback callback) {
    if (m_running) {
        return;
    }
    
    m_callback = callback;
    m_running = true;
    m_thread = std::thread(&HttplibHeartbeat::heartbeatLoop, this);
}

void HttplibHeartbeat::stop() {
    if (!m_running) {
        return;
    }
    
    m_running = false;
    if (m_thread.joinable()) {
        m_thread.join();
    }
}

void HttplibHeartbeat::setInterval(unsigned int interval) {
    m_interval = interval;
}

bool HttplibHeartbeat::isRunning() const {
    return m_running;
}

void HttplibHeartbeat::updateHeartbeatData(const std::map<std::string, std::string>& new_data) {
    m_heartbeat_data = new_data;
}

void HttplibHeartbeat::heartbeatLoop() {
    while (m_running) {
        std::string response;
        bool success = false;
        
        if (auto res = m_client->Get(m_endpoint.c_str())) {
            if (res->status == 200) {
                response = res->body;
                success = true;
            } else {
                response = "HTTP status: " + std::to_string(res->status);
            }
        } else {
            response = "Error: " + httplib::to_string(res.error());
        }
        
        if (m_callback) {
            m_callback(response, success);
        }
        
        // 等待下一次心跳
        for (unsigned int i = 0; i < m_interval && m_running; ++i) {
            std::this_thread::sleep_for(std::chrono::seconds(1));
        }
    }
}
/*
void HttplibHeartbeat::heartbeatLoop() {
    while (m_running) {
        json response_json;
        bool success = false;
        
        // 创建心跳JSON数据
        json request_json = createHeartbeatJson();
        std::string request_body = request_json.dump();
        
        // 设置JSON内容类型头
        httplib::Headers headers = {
            {"Content-Type", "application/json"}
        };
        
        if (auto res = m_client->Post(m_endpoint.c_str(), headers, request_body, "application/json")) {
            if (res->status == 200) {
                try {
                    response_json = json::parse(res->body);
                    success = true;
                } catch (const json::parse_error& e) {
                    response_json = {
                        {"error", "Failed to parse server response"},
                        {"details", e.what()},
                        {"raw_response", res->body}
                    };
                }
            } else {
                response_json = {
                    {"error", "HTTP request failed"},
                    {"status", res->status},
                    {"body", res->body}
                };
            }
        } else {
            response_json = {
                {"error", "Network error"},
                {"details", httplib::to_string(res.error())}
            };
        }
        
        if (m_callback) {
            m_callback(response_json, success);
        }
        
        // 等待下一次心跳
        for (unsigned int i = 0; i < m_interval && m_running; ++i) {
            std::this_thread::sleep_for(std::chrono::seconds(1));
        }
    }
}
*/
json HttplibHeartbeat::createHeartbeatJson() const {
    json j;
    j["type"] = "heartbeat";
    j["timestamp"] = std::chrono::duration_cast<std::chrono::milliseconds>(
        std::chrono::system_clock::now().time_since_epoch()).count();
    
    // 添加自定义心跳数据
    for (const auto& [key, value] : m_heartbeat_data) {
        j[key] = value;
    }
    
    return j;
}

使用实例

#include "HttplibHeartbeat.h"
#include <iostream>

int main() {
    // 创建心跳对象,连接localhost:8080,每5秒发送一次心跳
    HttplibHeartbeat heartbeat("localhost", 8080, "/api/heartbeat", 5);
    
    // 定义回调函数
    auto callback = [](const std::string& response, bool success) {
        if (success) {
            std::cout << "[Heartbeat] Success: " << response << std::endl;
        } else {
            std::cerr << "[Heartbeat] Failed: " << response << std::endl;
        }
    };
    
  /*  
    // 准备心跳数据
    std::map<std::string, std::string> heartbeat_data = {
        {"device_id", "12345"},
        {"version", "1.0.0"},
        {"status", "active"}
    };
    
    // 创建JSON心跳对象
    HttplibHeartbeat heartbeat("localhost", 8080, "/api/heartbeat", 10, heartbeat_data);
    // 定义回调函数
    auto callback = [](const json& response, bool success) {
        if (success) {
            std::cout << "[Heartbeat] Success. Server response:" << std::endl;
            std::cout << response.dump(4) << std::endl; // 漂亮打印JSON
            
            // 可以解析特定字段
            if (response.contains("next_check_interval")) {
                std::cout << "Next check in: " << response["next_check_interval"] << "s" << std::endl;
            }
        } else {
            std::cerr << "[Heartbeat] Failed. Error response:" << std::endl;
            std::cerr << response.dump(4) << std::endl;
        }
    };
    */
    
    // 启动心跳
    heartbeat.start(callback);
    
    std::cout << "Heartbeat started. Press Enter to stop..." << std::endl;
    std::cin.get();
    
    // 停止心跳
    heartbeat.stop();
    
    return 0;
}

编译说明

  1. 下载 cpp-httplib 头文件
  2. httplib.h 放在项目目录中
  3. 编译命令示例:g++ -std=c++11 HttplibHeartbeat.cpp main.cpp -lpthread -o heartbeat

网站公告

今日签到

点亮在社区的每一天
去签到