Files
front_linux/LFtid1056/client2.h

234 lines
8.0 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#ifndef CLIENT_H
#define CLIENT_H
#include <uv.h>
#include <string>
#include <vector>
#include <memory>
#include <unordered_map>
#include <mutex>
#include <queue>
#include "dealMsg.h"
#include "PQSMsg.h"
// 测点信息结构
struct PointInfo {
std::string point_id; // 测点ID
std::string name; // 测点名称
std::string device_id; // 所属装置ID
ushort nCpuNo; //测点序号 1-6
double PT1; // 电压变比1
double PT2; // 电压变比2
double CT1; // 电流变比1
double CT2; // 电流变比2
};
// 装置信息结构
struct DeviceInfo {
std::string device_id; // 装置ID
std::string name; // 装置名称
std::string model; // 装置型号
std::string mac; // 装置MAC地址
int status; // 运行状态 (0: 离线, 1: 在线)
std::vector<PointInfo> points; // 下属测点
};
enum class ConnectionState {
DISCONNECTED,
CONNECTING,
CONNECTED
};
// 添加的状态枚举
enum class DeviceState {
IDLE, // 空闲状态
READING_STATS, // 读取统计数据
READING_STATS_TIME, // 读取统计时间
READING_REALSTAT, // 读取实时数据
// 可根据需要添加更多状态
CUSTOM_ACTION // 自定义动作
};
// 状态动作结构体
struct StateAction {
DeviceState state;
std::vector<unsigned char> packet; // 该状态需要发送的报文
};
class ClientContext {
public:
uv_loop_t* loop;
uv_tcp_t client;
uv_timer_t timer;
uv_timer_t reconnect_timer;
ConnectionState state;
int reconnect_attempts;
volatile bool shutdown;
uint64_t last_state_query_time_ = 0; // 统计数据计时时间戳
uint64_t real_state_query_time_ = 0; // 实时数据计时时间戳
std::atomic<int> real_state_count{ 0 };//实时数据收发计数 原子操作保证线程安全
std::atomic<ushort> real_point_id_{ 1 }; // 新增:实时数据读取的测点序号(原子操作)
DeviceInfo device_info; // 装置信息
int cloudstatus; // 云前置登录状态0未登录 1已登录
// 新增状态管理成员
DeviceState current_state_; // 当前装置状态
uint64_t state_start_time_; // 状态开始时间(ms)
std::queue<StateAction> action_queue_; // 状态动作队列
std::mutex state_mutex_; // 状态操作互斥锁
std::vector<unsigned char> current_packet_; // 当前状态需要发送的报文
ClientContext(uv_loop_t* loop, const DeviceInfo& device, int index);
~ClientContext();
void init_tcp();//初始化客户端连接
void start_timer();//启动对应装置计时器 5秒执行一次
void start_reconnect_timer(int delay);//启动客户端重连定时
void stop_timers();//停止重连定时器
void close_handles();//关闭客户端各类连接与定时器
void append_and_process_data(const char* data, size_t len);//接收装置数据并存入缓冲
void put_packet_into_queue(const std::vector<unsigned char>& packet);//推送完整数据至处理队列
void change_state(DeviceState new_state, const std::vector<unsigned char>& packet = {});//改变装置状态和当前状态的待发送报文
void add_action(DeviceState state, const std::vector<unsigned char>& packet = {});//添加后续动作
void check_state_timeout();//装置状态超时检测
void process_next_action();//装置取后续工作并执行
void send_current_packet();//发送当前状态的报文至装置
// 新增: 多帧数据报文缓存
struct StatPacket {
int packet_index;
std::vector<unsigned char> data;
};
std::vector<StatPacket> stat_packets_cache_; // 缓存分帧报文
int expected_total_packets_ = 0; // 预期总帧数
std::mutex stat_cache_mutex_; // 缓存互斥锁
// 新增缓存管理方法
bool add_stat_packet(const std::vector<unsigned char>& packet, int current_packet, int total_packets);//插入多帧缓存数据
std::vector<StatPacket> get_and_clear_stat_packets();//取出所有缓存数据并清空缓存
void clear_stat_cache();//清空缓存
// 统计数据缓存
struct PointFloatCache {
std::array<tagPqData_Float, 4> data; // 存储四种数据类型(0-3)
std::array<bool, 4> received = { false }; // 标记四种数据类型是否已接收
};
// 测点统计浮点数据缓存映射表 (测点号 -> 缓存数据)
std::unordered_map<ushort, PointFloatCache> point_float_cache_;
std::mutex float_cache_mutex_; // 浮点缓存互斥锁
// 添加浮点数据到缓存
bool add_float_data(ushort point_id, int data_type, const tagPqData_Float& float_data);
// 获取并清除指定测点的完整浮点数据
std::array<tagPqData_Float, 4> get_and_clear_float_data(ushort point_id);
// 清除所有浮点数据缓存
void clear_float_cache();
private:
int index_;
private:
std::vector<unsigned char> recv_buffer_; // 接收数据缓冲区
std::mutex buffer_mutex_; // 缓冲区互斥锁
void process_buffer();
};
class ClientManager {
public:
static ClientManager& instance() {
static ClientManager inst;
return inst;
}
// 设置事件循环
void set_loop(uv_loop_t* loop) {
std::lock_guard<std::mutex> lock(mutex_);
loop_ = loop;
}
void add_device(const DeviceInfo& device);//添加一个装置连接
void remove_device(const std::string& device_id);//删除一个装置连接
bool send_to_device(const std::string& identifier, const unsigned char* data, size_t size);//选择指定的装置发送消息至服务端
void restart_device(const std::string& device_id);//关闭指定装置连接,等待重连唤起
void stop_all();//停止所有客户端连接
bool set_cloud_status(const std::string& identifier, int status);//修改云前置登录状态
bool post_message_processing(const std::string& identifier);// 消息处理完成后触发状态处理
// 添加状态动作到装置
bool add_action_to_device(const std::string& identifier,
DeviceState state,
const std::vector<unsigned char>& packet = {});
// 改变装置当前状态
bool change_device_state(const std::string& identifier,
DeviceState new_state,
const std::vector<unsigned char>& packet = {});
// 清除装置动作队列
bool clear_action_queue(const std::string& identifier);
// 获取装置当前状态
bool get_device_state(const std::string& identifier, DeviceState& out_state);
// 新增:通过标识符获取装置测点信息
bool get_device_points(const std::string& identifier,std::vector<PointInfo>& out_points);
//接收指定客户端的多帧报文并存入缓存区
bool add_stat_packet_to_device(const std::string& identifier,
const std::vector<unsigned char>& packet,
int current_packet,
int total_packets);
//获取指定客户端的所有缓存报文并清空缓存区
std::vector<ClientContext::StatPacket> get_and_clear_stat_packets(const std::string& identifier);
//清空多帧报文保存缓存区
bool clear_stat_cache(const std::string& identifier);
// 获取指定测点的PT和CT变比值
bool get_pt_ct_ratio(const std::string& identifier,
int16_t nCpuNo,
float& pt_ratio,
float& ct_ratio);
// 获取客户端数量
size_t client_count() {
std::lock_guard<std::mutex> lock(mutex_);
return clients_.size();
}
// 添加浮点数据到指定设备的缓存
bool add_float_data_to_device(const std::string& identifier,
ushort point_id,
int data_type,
const tagPqData_Float& float_data);
// 获取并清除指定测点的完整浮点数据
std::array<tagPqData_Float, 4> get_and_clear_float_data(
const std::string& identifier, ushort point_id);
// 清除设备的所有浮点缓存
bool clear_float_cache(const std::string& identifier);
// 新增:设置实时数据收发计数
bool set_real_state_count(const std::string& identifier, int count, ushort point_id = 1);
private:
ClientManager() : loop_(nullptr) {}
std::unordered_map<std::string, std::unique_ptr<ClientContext>> clients_;
std::mutex mutex_;
uv_loop_t* loop_; // 事件循环指针
};
// 函数声明
void start_client_connect(const std::vector<DeviceInfo>& devices);
void send_binary_data(ClientContext* ctx, const unsigned char* data, size_t data_size);
void on_timer(uv_timer_t* handle);
void try_reconnect(uv_timer_t* timer);
void on_connect(uv_connect_t* req, int status);
void on_close(uv_handle_t* handle);
void init_clients(uv_loop_t* loop, const std::vector<DeviceInfo>& devices);
void stop_all_clients();
#endif