HTTP实现心跳模块

news2025/4/16 8:00:56

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2334816.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

架构总览怎么写,才算工业级?

📈系统架构文档是整个项目最重要的起点,但很多人第一章就“写穿了”: 不是写得太细,就是没有重点。想要写出高质量、能协作、能传承的架构文档,这一篇会告诉你应该怎么做—— ✅ 架构总览的终极目标 明确边界、定义角色、画清数据流 别讲执行细节,别深入函数调用。 ✅ 架…

Datawhale 入驻 GitCode:以开源力量推动 AI 教育公平与创新

在 AI 技术深度重塑教育生态的今天&#xff0c;国内首个 AI 开源学习社区 —— Datawhale 正式加入 GitCode 开源平台&#xff01;作为覆盖全球 3000 高校、培养超百万 AI 人才的创新社区&#xff0c;Datawhale 将通过开源协作模式&#xff0c;为人工智能教育公平注入新动能&a…

ChatDBA:一个基于AI的智能数据库助手

今天给大家介绍一个基于 AI 大语言模型实现数据库故障诊断的智能助手&#xff1a;ChatDBA。 ChatDBA 是由上海爱可生信息技术股份有限公司开发&#xff0c;通过对话交互&#xff0c;提供数据库故障诊断、专业知识学习、SQL 生成和优化等功能&#xff0c;旨在提升 DBA 工作效率。…

MacOS中的鼠标、触控板的设置研究

一、背景和写这篇文章的原因 想搞清楚和配置好鼠标&#xff0c;比如解决好为什么我的滚动那么难用&#xff1f;怎么设置滚轮的方向跟windows相同&#xff1f;调整双击速度&#xff0c;调整鼠标滚轮左右拨动的"冷却时间"。 二、各种设置之详细解释 1. MacOS设置 -&…

asp.net core 项目发布到 IIS 服务器

目录 一、VS2022 发布 二、设置IIS服务 三、配置IIS管理器 &#xff08;一&#xff09;打开IIS管理器 &#xff08;二&#xff09;添加站台 &#xff08;三&#xff09;配置应用程式集区 四、安装ASP.NET Core Hosting Bundle 五、设定IIS的日志位置 六、测试 一、VS2…

【Nodebb系列】Nodebb笔记写入方案

NodeBB写入方案 前言 最近在整理以前记录的碎片笔记&#xff0c;想把它们汇总到NodeBB中&#xff0c;方便管理和浏览。但是笔记内容有点多&#xff0c;并且用发帖的形式写到NodeBB中会丢失时间信息&#xff0c;因此整理了一套NodeBB写入方案&#xff0c;大致流程如下&#xf…

计算机视觉——基于YOLOV8 的人体姿态估计训练与推理

概述 自 Ultralytics 发布 YOLOV5 之后&#xff0c;YOLO 的应用方向和使用方式变得更加多样化且简单易用。从图像分类、目标检测、图像分割、目标跟踪到关键点检测&#xff0c;YOLO 几乎涵盖了计算机视觉的各个领域&#xff0c;似乎已经成为计算机视觉领域的“万能工具”。 Y…

鸿蒙小案例---心情日记

效果演示 代码实现 import { router, window } from kit.ArkUIEntry Component struct Index {async aboutToAppear(): Promise<void> {let w await window.getLastWindow(getContext())w.setWindowSystemBarProperties({statusBarColor: #00C6C3,statusBarContentColo…

el-tree 实现树形菜单子级取消选中后父级选中效果不变

背景 在复杂的企业级管理系统中,树形菜单是一种常见的数据展示和交互组件。传统的树形菜单通常存在以下交互局限: 子节点取消选中时,父节点会自动取消选中无法满足复杂的权限分配和数据筛选场景实际应用场景: 组织架构权限管理多层级资源分配复杂的数据筛选与展示实现需求…

Java虚拟机——JVM(Java Virtual Machine)解析一

1.JVM是什么&#xff1f; 1.1 JVM概念 Java Virtual Machine (JVM) 是JDK的核心组件之一&#xff0c;它使得 Java 程序能够在任何支持 JVM 的设备或操作系统上运行&#xff0c;而无需修改源代码 JDK是什么&#xff0c;JDK和JVM是什么关系&#xff1f;1.Java IDE(Integrated …

【源码】SpringMvc源码分析

文章目录 SpringMVC 基础回顾​核心组件源码分析​DispatcherServlet​HandlerMapping​HandlerAdapter​ViewResolver​ 请求处理流程源码解析​ 在当今的 Java Web 开发领域&#xff0c;SpringMVC 无疑是最为广泛应用的 Web 框架之一。它以其强大的功能、灵活的配置以及高度的…

tcp特点+TCP的状态转换图+time_wait详解

tcp特点TCP的状态转换图time wait详解 目录 一、tcp特点解释 1.1 面向连接 1.1.1 连接建立——三次握手 1.1.2 连接释放——四次挥手 1.2 可靠的 1.2.1 应答确认 1.2.2 超时重传 1.2.3 乱序重排 1.2.4 去重 1.2.5 滑动窗口进行流量控制 1.3 流失服务&#xff08;字节…

高支模自动化监测解决方案

1.行业现状 高大模板支撑系统在浇筑施工过程中&#xff0c;诸多重大安全风险点进行实时自动化安全监测的解决方案主要监测由于顶杆失稳、扣件失效、承压过大等引起的支撑轴力、模板沉降、相对位移、支撑体系倾斜等参数变化。系统采用无线自动组网、高频连续采样&#xff0c;实时…

OpenCV 图形API(24)图像滤波-----双边滤波函数bilateralFilter()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 应用双边滤波到图像。 该函数对输入图像应用双边滤波&#xff0c;如 http://www.dai.ed.ac.uk/CVonline/LOCAL_COPIES/MANDUCHI1/Bilateral_Fil…

HarmonyOS中的多线程并发机制

目录 多线程并发1. 多线程并发概述2 多线程并发模型3 TaskPool简介4 Worker简介4.1 Woker注意事项4.2 Woker基本用法示例 5. TaskPool和Worker的对比5.1 实现特点对比5.2 适用场景对比 多线程并发 1. 多线程并发概述 并发模型是用来实现不同应用场景中并发任务的编程模型&…

【随手笔记】QT避坑一(串口readyRead信号不产生)

问题描述&#xff1a; 使用QT5.15.2版本 测试串口readyRead绑定槽函数&#xff0c;接收到数据后 不能触发 试了很多网友的程序&#xff0c;他们的发布版本可以&#xff0c;但是源码我编译后就不能触发&#xff0c;判断不是代码的问题 看到有人提到QT版本的问题&#xff0c;于…

【产品】ToB产品需求分析

需求分析流程 合格产品经理 帮助用户、引导用户、分析需求、判断需求、设计方案 不能苛求用户提出合理、严谨的需求&#xff0c;这不是用户的责任和义务&#xff0c;而应该通过自己的专业能力来完成需求的采集工作 #mermaid-svg-ASu8vocank48X6FI {font-family:"trebuche…

驱动开发硬核特训 · Day 10 (理论上篇):设备模型 ≈ 运行时的适配器机制

&#x1f50d; B站相应的视屏教程&#xff1a; &#x1f4cc; 内核&#xff1a;博文视频 - 总线驱动模型实战全解析 敬请关注&#xff0c;记得标为原始粉丝。 在 Linux 驱动开发中&#xff0c;设备模型&#xff08;Device Model&#xff09;是理解驱动架构的核心。而从软件工程…

flutter 打包mac程序 dmg教程

✅ 前提条件 ✅ 你已经在 macOS 上安装了 Android Studio Flutter SDK。 ✅ Flutter 支持 macOS 构建。 运行下面命令确认是否支持&#xff1a; Plain Text bash 复制编辑 flutter doctor ---## &#x1f9f1; 第一步&#xff1a;启用 macOS 支持如果是新项目&#xff0c;…

【数据结构与算法】——堆(补充)

前言 上一篇文章讲解了堆的概念和堆排序&#xff0c;本文是对堆的内容补充 主要包括&#xff1a;堆排序的时间复杂度、TOP 这里写目录标题 前言正文堆排序的时间复杂度TOP-K 正文 堆排序的时间复杂度 前文提到&#xff0c;利用堆的思想完成的堆排序的代码如下&#xff08;包…