HTTP实现心跳模块
使用轻量级的c++HTTP库cpp-httplib重现实现HTTP心跳模块
头文件HttplibHeartbeat.h
cpp
#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
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;
}
使用实例
cpp
#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;
}
编译说明
- 下载 cpp-httplib 头文件
- 将
httplib.h
放在项目目录中 - 编译命令示例:
g++ -std=c++11 HttplibHeartbeat.cpp main.cpp -lpthread -o heartbeat