403 lines
12 KiB
C++
403 lines
12 KiB
C++
#include "client2.h"
|
|
#include "PQSMsg.h"
|
|
#include "dealMsg.h"
|
|
#include <iostream>
|
|
#include <cmath>
|
|
#include <cstring>
|
|
#include <cstdlib>
|
|
#include <vector>
|
|
#include <memory>
|
|
#include <mutex>
|
|
#include <unordered_map>
|
|
|
|
// 配置参数
|
|
constexpr int BASE_RECONNECT_DELAY = 5000; // 基础重连延迟(ms)
|
|
constexpr int MAX_RECONNECT_DELAY = 60000; // 最大重连延迟(ms)
|
|
constexpr const char* SERVER_IP = "172.25.144.1"; // 目标服务器IP"101.132.39.45"
|
|
constexpr int SERVER_PORT = 61000; // 目标服务器端口1056
|
|
|
|
static uv_loop_t* global_loop = nullptr;
|
|
static uv_timer_t monitor_timer;
|
|
extern SafeMessageQueue message_queue;
|
|
|
|
// ClientContext 实现
|
|
ClientContext::ClientContext(uv_loop_t* loop, const DeviceInfo& device, int index)
|
|
: loop(loop), state(ConnectionState::DISCONNECTED),
|
|
reconnect_attempts(0), shutdown(false), device_info(device), index_(index) {
|
|
|
|
// 初始化 TCP 句柄
|
|
uv_tcp_init(loop, &client);
|
|
client.data = this;
|
|
|
|
// 初始化定时器
|
|
uv_timer_init(loop, &timer);
|
|
timer.data = this;
|
|
|
|
// 初始化重连定时器
|
|
uv_timer_init(loop, &reconnect_timer);
|
|
reconnect_timer.data = this;
|
|
}
|
|
|
|
ClientContext::~ClientContext() {
|
|
stop_timers();
|
|
close_handles();
|
|
}
|
|
|
|
void ClientContext::init_tcp() {
|
|
if (!uv_is_active((uv_handle_t*)&client)) {
|
|
uv_tcp_init(loop, &client);
|
|
client.data = this;
|
|
}
|
|
}
|
|
|
|
void ClientContext::start_timer() {
|
|
if (!uv_is_active((uv_handle_t*)&timer)) {
|
|
uv_timer_start(&timer, on_timer, 6000, 6000);
|
|
}
|
|
}
|
|
|
|
void ClientContext::start_reconnect_timer(int delay) {
|
|
if (!uv_is_active((uv_handle_t*)&reconnect_timer)) {
|
|
uv_timer_start(&reconnect_timer, try_reconnect, delay, 0);
|
|
}
|
|
}
|
|
|
|
void ClientContext::stop_timers() {
|
|
if (uv_is_active((uv_handle_t*)&timer)) uv_timer_stop(&timer);
|
|
if (uv_is_active((uv_handle_t*)&reconnect_timer)) uv_timer_stop(&reconnect_timer);
|
|
}
|
|
|
|
void ClientContext::close_handles() {
|
|
if (!uv_is_closing((uv_handle_t*)&client)) {
|
|
uv_close((uv_handle_t*)&client, nullptr);
|
|
}
|
|
if (!uv_is_closing((uv_handle_t*)&timer)) {
|
|
uv_close((uv_handle_t*)&timer, nullptr);
|
|
}
|
|
if (!uv_is_closing((uv_handle_t*)&reconnect_timer)) {
|
|
uv_close((uv_handle_t*)&reconnect_timer, nullptr);
|
|
}
|
|
}
|
|
|
|
/* 缓冲区分配回调 */
|
|
void alloc_buffer(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) {
|
|
buf->base = new char[suggested_size];
|
|
buf->len = suggested_size;
|
|
}
|
|
|
|
/* 数据读取回调 */
|
|
void on_read(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) {
|
|
ClientContext* ctx = static_cast<ClientContext*>(stream->data);
|
|
|
|
if (nread < 0) {
|
|
if (nread != UV_EOF) {
|
|
std::cerr << "[Device " << ctx->device_info.device_id
|
|
<< "] RECV ERROR: " << uv_strerror(nread) << std::endl;
|
|
}
|
|
uv_close((uv_handle_t*)stream, on_close);
|
|
delete[] buf->base;
|
|
return;
|
|
}
|
|
|
|
if (nread > 0) {
|
|
// 将接收到的数据放入消息队列
|
|
deal_message_t msg;
|
|
msg.device_id = ctx->device_info.device_id; // 直接赋值
|
|
msg.mac = ctx->device_info.mac; // 直接赋值
|
|
|
|
// 复制测点信息
|
|
msg.points = ctx->device_info.points;
|
|
|
|
msg.data = static_cast<char*>(malloc(nread));
|
|
msg.length = nread;
|
|
memcpy(msg.data, buf->base, nread);
|
|
|
|
if (!message_queue.push(msg)) {
|
|
std::cerr << "[Device " << ctx->device_info.device_id
|
|
<< "] Message queue full, dropping message" << std::endl;
|
|
free(msg.data);
|
|
}
|
|
std::cout << "on_read: " << ctx->device_info.mac << " get!" << std::endl;
|
|
}
|
|
|
|
delete[] buf->base;
|
|
}
|
|
|
|
/* 数据写入回调 */
|
|
void on_write(uv_write_t* req, int status) {
|
|
ClientContext* ctx = static_cast<ClientContext*>(req->handle->data);
|
|
|
|
if (status < 0) {
|
|
std::cerr << "[Device " << ctx->device_info.device_id
|
|
<< "] SEND ERROR: " << uv_strerror(status) << std::endl;
|
|
}
|
|
std::cout << "on_write: " << ctx->device_info.mac << " down!" << std::endl;
|
|
delete[] static_cast<char*>(req->data); // 释放发送数据缓冲区
|
|
delete req; // 释放写入请求
|
|
}
|
|
|
|
/* 定时发送回调 */
|
|
void on_timer(uv_timer_t* handle) {
|
|
ClientContext* ctx = static_cast<ClientContext*>(handle->data);
|
|
|
|
if (ctx->state != ConnectionState::CONNECTED) {
|
|
return;
|
|
}
|
|
std::cout << "on_timer: " << ctx->device_info.mac << " send!"<< std::endl;
|
|
// 使用装置自己的MAC地址生成登录报文
|
|
auto binary_data = generate_frontlogin_message(ctx->device_info.mac);
|
|
|
|
// 调用发送函数
|
|
send_binary_data(ctx, binary_data.data(), binary_data.size());
|
|
|
|
//ClientManager::instance().send_to_device(ctx->device_info.mac, binary_data.data(), binary_data.size());
|
|
|
|
// 根据装置状态发送其他数据
|
|
if (ctx->device_info.status == 1) { // 在线状态
|
|
// 可以发送装置配置信息或测点数据
|
|
}
|
|
}
|
|
|
|
/* 发送二进制报文函数 */
|
|
void send_binary_data(ClientContext* ctx, const unsigned char* data, size_t data_size) {
|
|
if (ctx->state != ConnectionState::CONNECTED) {
|
|
std::cerr << "[Device " << ctx->device_info.device_id
|
|
<< "] Cannot send: not connected" << std::endl;
|
|
return;
|
|
}
|
|
|
|
uv_buf_t buf = uv_buf_init(const_cast<char*>(reinterpret_cast<const char*>(data)), data_size);
|
|
uv_write_t* write_req = new uv_write_t;
|
|
|
|
// 复制数据以确保安全
|
|
char* data_copy = new char[data_size];
|
|
memcpy(data_copy, data, data_size);
|
|
write_req->data = data_copy;
|
|
|
|
int ret = uv_write(write_req, (uv_stream_t*)&ctx->client, &buf, 1, on_write);
|
|
if (ret < 0) {
|
|
std::cerr << "[Device " << ctx->device_info.device_id
|
|
<< "] uv_write failed: " << uv_strerror(ret) << std::endl;
|
|
delete[] data_copy;
|
|
delete write_req;
|
|
}
|
|
}
|
|
|
|
/* 连接关闭回调 */
|
|
void on_close(uv_handle_t* handle) {
|
|
ClientContext* ctx = static_cast<ClientContext*>(handle->data);
|
|
ctx->state = ConnectionState::DISCONNECTED;
|
|
std::cerr << "[Device " << ctx->device_info.device_id << "] Connection closed" << std::endl;
|
|
|
|
ctx->stop_timers();
|
|
|
|
if (!ctx->shutdown) {
|
|
int delay = BASE_RECONNECT_DELAY * pow(2, ctx->reconnect_attempts);
|
|
delay = delay > MAX_RECONNECT_DELAY ? MAX_RECONNECT_DELAY : delay;
|
|
|
|
std::cout << "[Device " << ctx->device_info.device_id
|
|
<< "] Reconnecting in " << delay << "ms (attempt "
|
|
<< ctx->reconnect_attempts + 1 << ")" << std::endl;
|
|
|
|
ctx->reconnect_attempts++;
|
|
ctx->start_reconnect_timer(delay);
|
|
}
|
|
}
|
|
|
|
/* 尝试重连 */
|
|
void try_reconnect(uv_timer_t* timer) {
|
|
ClientContext* ctx = static_cast<ClientContext*>(timer->data);
|
|
|
|
if (ctx->state != ConnectionState::DISCONNECTED || ctx->shutdown) {
|
|
return;
|
|
}
|
|
|
|
std::cerr << "[Device " << ctx->device_info.device_id << "] Attempting reconnect" << std::endl;
|
|
|
|
ctx->init_tcp();
|
|
ctx->state = ConnectionState::CONNECTING;
|
|
|
|
struct sockaddr_in addr;
|
|
uv_ip4_addr(SERVER_IP, SERVER_PORT, &addr);
|
|
|
|
uv_connect_t* req = new uv_connect_t;
|
|
req->data = ctx;
|
|
|
|
int ret = uv_tcp_connect(req, &ctx->client, (const struct sockaddr*)&addr, on_connect);
|
|
if (ret < 0) {
|
|
std::cerr << "[Device " << ctx->device_info.device_id
|
|
<< "] Connect error: " << uv_strerror(ret) << std::endl;
|
|
delete req;
|
|
uv_close((uv_handle_t*)&ctx->client, on_close);
|
|
}
|
|
}
|
|
|
|
/* 连接建立回调 */
|
|
void on_connect(uv_connect_t* req, int status) {
|
|
ClientContext* ctx = static_cast<ClientContext*>(req->data);
|
|
delete req;
|
|
|
|
if (status < 0) {
|
|
std::cerr << "[Device " << ctx->device_info.device_id
|
|
<< "] Connect failed: " << uv_strerror(status) << std::endl;
|
|
if (!uv_is_closing((uv_handle_t*)&ctx->client)) {
|
|
uv_close((uv_handle_t*)&ctx->client, on_close);
|
|
}
|
|
return;
|
|
}
|
|
|
|
std::cerr << "[Device " << ctx->device_info.device_id << "] Connected to server" << std::endl;
|
|
|
|
ctx->state = ConnectionState::CONNECTED;
|
|
ctx->reconnect_attempts = 0;
|
|
|
|
uv_read_start((uv_stream_t*)&ctx->client, alloc_buffer, on_read);
|
|
ctx->start_timer();
|
|
}
|
|
|
|
/* 初始化所有客户端连接 */
|
|
void init_clients(uv_loop_t* loop, const std::vector<DeviceInfo>& devices) {
|
|
auto& manager = ClientManager::instance();
|
|
manager.set_loop(loop); // 使用公共方法设置事件循环
|
|
|
|
for (const auto& device : devices) {
|
|
manager.add_device(device);
|
|
}
|
|
}
|
|
|
|
/* 停止所有客户端 */
|
|
void stop_all_clients() {
|
|
auto& manager = ClientManager::instance();
|
|
manager.stop_all();
|
|
}
|
|
|
|
/* 连接监控回调 */
|
|
void monitor_connections(uv_timer_t* handle) {
|
|
static int recovery_counter = 0;
|
|
if (++recovery_counter >= 5) {
|
|
int active_count = 0;
|
|
auto& manager = ClientManager::instance();
|
|
size_t total_clients = manager.client_count();
|
|
|
|
// 实际应用中,这里需要实现获取活动连接数的方法
|
|
// 简化处理,只显示总连接数
|
|
std::cout << "Total connections: " << total_clients << std::endl;
|
|
recovery_counter = 0;
|
|
}
|
|
}
|
|
|
|
static void close_walk_cb(uv_handle_t* handle, void* arg) {
|
|
if (!uv_is_closing(handle)) {
|
|
uv_close(handle, nullptr);
|
|
}
|
|
}
|
|
|
|
/* 启动客户端连接 */
|
|
void start_client_connect(const std::vector<DeviceInfo>& devices) {
|
|
// 创建全局事件循环
|
|
global_loop = uv_default_loop();
|
|
|
|
// 初始化所有客户端
|
|
init_clients(global_loop, devices);
|
|
|
|
// 启动连接监控
|
|
uv_timer_init(global_loop, &monitor_timer);
|
|
uv_timer_start(&monitor_timer, monitor_connections, 1000, 1000);
|
|
|
|
// 运行事件循环
|
|
uv_run(global_loop, UV_RUN_DEFAULT);
|
|
|
|
// 添加资源清理阶段
|
|
while (uv_loop_alive(global_loop)) {
|
|
uv_run(global_loop, UV_RUN_ONCE);
|
|
}
|
|
|
|
// 安全关闭事件循环
|
|
int err = uv_loop_close(global_loop);
|
|
if (err) {
|
|
std::cerr << "uv_loop_close error: " << uv_strerror(err) << std::endl;
|
|
// 强制清理残留句柄(调试用)
|
|
uv_walk(global_loop, close_walk_cb, nullptr);
|
|
uv_run(global_loop, UV_RUN_NOWAIT);
|
|
}
|
|
|
|
// 清理所有客户端
|
|
stop_all_clients();
|
|
global_loop = nullptr;
|
|
}
|
|
|
|
// ClientManager 成员函数实现
|
|
void ClientManager::add_device(const DeviceInfo& device) {
|
|
std::lock_guard<std::mutex> lock(mutex_);
|
|
|
|
if (!loop_) {
|
|
std::cerr << "[Device " << device.device_id << "] Cannot add: event loop not set\n";
|
|
return;
|
|
}
|
|
|
|
// 检查是否已存在相同ID的装置
|
|
if (clients_.find(device.device_id) != clients_.end()) {
|
|
std::cerr << "[Device " << device.device_id << "] Already exists, skip adding\n";
|
|
return;
|
|
}
|
|
|
|
// 创建新的客户端上下文
|
|
int index = clients_.size();
|
|
auto ctx = std::unique_ptr<ClientContext>(new ClientContext(loop_, device, index));
|
|
|
|
// 添加到管理映射
|
|
clients_[device.device_id] = std::move(ctx);
|
|
|
|
// 启动连接
|
|
try_reconnect(&clients_[device.device_id]->reconnect_timer);
|
|
std::cout << "[Device " << device.device_id << "] Added successfully\n";
|
|
}
|
|
|
|
void ClientManager::remove_device(const std::string& device_id) {
|
|
std::lock_guard<std::mutex> lock(mutex_);
|
|
|
|
auto it = clients_.find(device_id);
|
|
if (it == clients_.end()) {
|
|
std::cerr << "[Device " << device_id << "] Not found, cannot remove\n";
|
|
return;
|
|
}
|
|
|
|
// 关闭连接并移除
|
|
it->second->shutdown = true;
|
|
it->second->close_handles();
|
|
clients_.erase(it);
|
|
std::cout << "[Device " << device_id << "] Removed successfully\n";
|
|
}
|
|
|
|
bool ClientManager::send_to_device(const std::string& identifier,
|
|
const unsigned char* data,
|
|
size_t size) {
|
|
std::lock_guard<std::mutex> lock(mutex_);
|
|
|
|
for (auto& pair : clients_) {
|
|
auto& ctx = pair.second;
|
|
// 匹配装置ID或MAC地址
|
|
if (ctx->device_info.device_id == identifier ||
|
|
ctx->device_info.mac == identifier) {
|
|
|
|
if (ctx->state == ConnectionState::CONNECTED) {
|
|
send_binary_data(ctx.get(), data, size);
|
|
return true;
|
|
}
|
|
std::cerr << "[Device " << identifier << "] Not connected\n";
|
|
return false;
|
|
}
|
|
}
|
|
|
|
std::cerr << "[Device " << identifier << "] Not found\n";
|
|
return false;
|
|
}
|
|
|
|
void ClientManager::stop_all() {
|
|
std::lock_guard<std::mutex> lock(mutex_);
|
|
for (auto& pair : clients_) {
|
|
pair.second->shutdown = true;
|
|
pair.second->close_handles();
|
|
}
|
|
clients_.clear();
|
|
} |