From 4bd984a540807f11f3c18bacb6e59dbacc6266c7 Mon Sep 17 00:00:00 2001 From: sladro Date: Wed, 28 Jan 2026 09:56:53 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8Dbug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CMakeLists.txt | 86 +++++++++++++++----- src/collector/DataCollector.cpp | 15 +++- src/collector/DataCollector.h | 2 + src/core/System.cpp | 50 +++++++----- src/core/System.h | 4 + src/network/TrafficLightTcpServer.cpp | 94 +++++++++++++++++++++ src/network/TrafficLightTcpServer.h | 40 +++++++++ system_config.json | 113 ++++++++++++++++++++++++++ tcp_server.py | 34 ++++++++ 9 files changed, 395 insertions(+), 43 deletions(-) create mode 100644 src/network/TrafficLightTcpServer.cpp create mode 100644 src/network/TrafficLightTcpServer.h create mode 100644 system_config.json create mode 100644 tcp_server.py diff --git a/CMakeLists.txt b/CMakeLists.txt index a813d59..1d4dd67 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,6 +11,12 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON) project(collision_avoidance) +# 静态链接选项: +# - 优先静态链接 Boost(以及可选的 libcurl,取决于系统是否提供静态库) +# - 同时静态链接 libstdc++/libgcc,减少目标机运行时依赖 +option(LINK_STATIC_DEPS "Prefer static linking for third-party deps when available" OFF) +option(FULL_STATIC "Link fully static binary (-static). Requires static libs (glibc-static, libcurl.a, etc.)" OFF) + set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) @@ -35,14 +41,29 @@ set(Boost_NO_WARN_NEW_VERSIONS 1) set(Boost_USE_STATIC_LIBS OFF) set(Boost_USE_MULTITHREADED ON) set(Boost_USE_STATIC_RUNTIME OFF) + +if(LINK_STATIC_DEPS) + set(Boost_USE_STATIC_LIBS ON) + # libcurl 静态库在 CentOS 7 上可能需要额外的 -devel/-static 包支持;若不存在,FindCURL 仍会回退到动态库 + set(CURL_USE_STATIC_LIBS ON) +endif() if(NOT APPLE) - # 在 CentOS 上使用 Boost 1.69 - set(BOOST_ROOT "/usr/include/boost169") - set(BOOST_LIBRARYDIR "/usr/lib64/boost169") + # 允许外部通过 -DBOOST_ROOT/-DBOOST_LIBRARYDIR 覆盖(例如容器内自编译 Boost 到 /opt/boost-1.69) + if(NOT DEFINED BOOST_ROOT) + # 旧环境默认(若存在 boost169 包) + set(BOOST_ROOT "/usr/include/boost169") + endif() + if(NOT DEFINED BOOST_LIBRARYDIR) + set(BOOST_LIBRARYDIR "/usr/lib64/boost169") + endif() else() - # 在 macOS 上使用 Homebrew 安装的 Boost - set(BOOST_ROOT "/opt/homebrew/Cellar/boost/1.87.0") - set(BOOST_LIBRARYDIR "/opt/homebrew/Cellar/boost/1.87.0/lib") + # 在 macOS 上使用 Homebrew 安装的 Boost(同样允许外部覆盖) + if(NOT DEFINED BOOST_ROOT) + set(BOOST_ROOT "/opt/homebrew/Cellar/boost/1.87.0") + endif() + if(NOT DEFINED BOOST_LIBRARYDIR) + set(BOOST_LIBRARYDIR "/opt/homebrew/Cellar/boost/1.87.0/lib") + endif() endif() # 设置 CMake 策略(在 find_package(Boost) 前添加) @@ -63,26 +84,17 @@ find_package(Boost 1.69.0 REQUIRED COMPONENTS # 添加 libcurl find_package(CURL REQUIRED) -# 修改 JSON 库配置为双模式 -if(APPLE) - # macOS 使用 FetchContent +# JSON 库:优先使用系统包;不可用时 fallback 到 FetchContent(CentOS 7 通常没有 nlohmann-json-devel) +find_package(nlohmann_json QUIET) + +if(NOT TARGET nlohmann_json::nlohmann_json) FetchContent_Declare( nlohmann_json GIT_REPOSITORY https://github.com/nlohmann/json.git GIT_TAG v3.11.3 + GIT_SHALLOW TRUE ) FetchContent_MakeAvailable(nlohmann_json) -else() - # CentOS 使用系统安装的包 - find_package(nlohmann_json REQUIRED) - - # 验证系统包路径 - if(NOT TARGET nlohmann_json::nlohmann_json) - message(FATAL_ERROR "系统未安装正确版本的 nlohmann_json") - endif() - - # 添加手动包含路径(适用于旧版CMake) - include_directories(${nlohmann_json_INCLUDE_DIRS}) endif() # 源文件列表 @@ -96,6 +108,7 @@ set(LIB_SOURCES src/network/WebSocketServer.cpp src/network/HTTPClient.cpp src/network/TrafficLightHttpServer.cpp + src/network/TrafficLightTcpServer.cpp src/spatial/CoordinateConverter.cpp src/types/BasicTypes.cpp src/types/VehicleData.cpp @@ -126,15 +139,46 @@ target_link_libraries(${PROJECT_NAME}_lib Boost::atomic Boost::regex nlohmann_json::nlohmann_json - CURL::libcurl Threads::Threads -pthread ) +# CURL 链接:全静态时优先使用 CURL_LIBRARY/CURL_LIBRARIES(避免使用可能指向错误路径的导入目标) +if(FULL_STATIC) + if(CURL_INCLUDE_DIR) + target_include_directories(${PROJECT_NAME}_lib PUBLIC ${CURL_INCLUDE_DIR}) + endif() + if(CURL_LIBRARY) + target_link_libraries(${PROJECT_NAME}_lib PUBLIC ${CURL_LIBRARY}) + else() + target_link_libraries(${PROJECT_NAME}_lib PUBLIC ${CURL_LIBRARIES}) + endif() +else() + if(TARGET CURL::libcurl) + target_link_libraries(${PROJECT_NAME}_lib PUBLIC CURL::libcurl) + else() + target_link_libraries(${PROJECT_NAME}_lib PUBLIC ${CURL_LIBRARIES}) + endif() +endif() + +if(LINK_STATIC_DEPS) + # FindCURL 在静态场景下通常不会把 libcurl 的传递依赖带出来;这里补充常见依赖。 + # 若链接仍报缺库,可用你自编的 curl: `curl-config --static-libs` 得到完整列表再补齐。 + target_link_libraries(${PROJECT_NAME}_lib PUBLIC dl z ssl crypto rt resolv) +endif() + # 创建主可执行文件 add_executable(${PROJECT_NAME} src/main.cpp) target_link_libraries(${PROJECT_NAME} PRIVATE ${PROJECT_NAME}_lib) +if(LINK_STATIC_DEPS) + target_link_options(${PROJECT_NAME} PRIVATE -static-libstdc++ -static-libgcc) +endif() + +if(FULL_STATIC) + target_link_options(${PROJECT_NAME} PRIVATE -static) +endif() + # 添加一个选项来控制是否编译测试 if(APPLE) option(BUILD_TESTS "Build test cases" ON) diff --git a/src/collector/DataCollector.cpp b/src/collector/DataCollector.cpp index 451dd01..c5fef5b 100644 --- a/src/collector/DataCollector.cpp +++ b/src/collector/DataCollector.cpp @@ -56,7 +56,7 @@ void DataCollector::start() { // 启动三个独立的采集线程 positionThread_ = std::thread(&DataCollector::positionLoop, this); unmannedThread_ = std::thread(&DataCollector::unmannedLoop, this); - trafficLightThread_ = std::thread(&DataCollector::trafficLightLoop, this); + // 红绿灯改为 TCP 被动接收注入(不再轮询拉取) } void DataCollector::stop() { @@ -443,6 +443,19 @@ std::vector DataCollector::getTrafficLightSignals() { return trafficLightCache_; } +void DataCollector::injectTrafficLightSignals(std::vector signals) { + { + std::lock_guard lock(cacheMutex_); + trafficLightCache_ = std::move(signals); + if (!trafficLightCache_.empty()) { + lastTrafficLightTimestamp_ = trafficLightCache_[0].timestamp; + } + } + + // 用于超时检测:收到推送即认为链路正常 + last_traffic_light_fetch_ = std::chrono::steady_clock::now(); +} + bool DataCollector::fetchTrafficLightSignals( std::vector& signals) { if (!dataSource_) { diff --git a/src/collector/DataCollector.h b/src/collector/DataCollector.h index 70e505b..d2d3815 100644 --- a/src/collector/DataCollector.h +++ b/src/collector/DataCollector.h @@ -44,6 +44,8 @@ public: std::vector getAircraftData(); std::vector getVehicleData(); std::vector getTrafficLightSignals(); + // TCP 推送模式下由外部注入红绿灯信号(替代轮询拉取) + void injectTrafficLightSignals(std::vector signals); bool fetchTrafficLightSignals(std::vector& signals); bool fetchUnmannedVehicleStatus(const std::string& vehicle_id, std::string& status); bool fetchPositionData(); // 获取位置数据 diff --git a/src/core/System.cpp b/src/core/System.cpp index 89848a1..d46fd16 100644 --- a/src/core/System.cpp +++ b/src/core/System.cpp @@ -56,28 +56,21 @@ bool System::initialize() { ws_thread_ = std::thread([this]() { ws_server_->start(); }); Logger::info("WebSocket server initialized on port ", system_config.websocket.port); - // 新增: 初始化并启动红绿灯 HTTP 服务器 - try { - traffic_light_http_server_ = std::make_unique( - system_config.traffic_light_server.port, - system_config.traffic_light_server.max_connections, - ".", - *this - ); - // Start server in its own thread (start itself handles creating internal threads for io_context) - traffic_light_http_server_thread_ = std::thread([this]() { + // 红绿灯改为 TCP 被动接收(对齐 tcp_server.py:accept -> recv -> 响应 -> close) + // 这里先写死监听端口 8082(0.0.0.0),用于你先在测试平台验证链路 + traffic_light_tcp_server_ = std::make_unique( + static_cast(8082), + [this](const std::string& payload) { + Logger::info("Received traffic light TCP payload: ", payload); try { - traffic_light_http_server_->start(2); // Use 2 threads for IO context - } catch (const std::exception& e) { - Logger::error("TrafficLightHttpServer thread failed to start: ", e.what()); + // 如果对端发的是 JSON(包含 DI-11~DI-16),沿用现有 DI 解析逻辑 + nlohmann::json di = nlohmann::json::parse(payload); + processPushedTrafficLightData(di); + } catch (...) { + // 非 JSON:先只记录,后续再按现场协议补解析 } - }); - Logger::info("Traffic light HTTP server initialized on port ", system_config.traffic_light_server.port); - } catch (const std::exception& e) { - Logger::error("Failed to initialize Traffic Light HTTP Server: ", e.what()); - // Decide if this failure is critical - return false; // Example: treat as critical - } + } + ); // 加载机场区域配置 airportBounds_ = std::make_unique("config/airport_bounds.json"); @@ -143,6 +136,11 @@ void System::start() { running_ = true; dataCollector_->start(); + + if (traffic_light_tcp_server_) { + traffic_light_tcp_server_->start(); + } + processThread_ = std::thread(&System::processLoop, this); Logger::info("System processing loop started"); } @@ -164,7 +162,12 @@ void System::stop() { ws_thread_.join(); } - // 新增: Stop Traffic Light HTTP Server + // Stop Traffic Light servers + if (traffic_light_tcp_server_) { + traffic_light_tcp_server_->stop(); + } + + // 保留旧 HTTP server 成员(当前不启用) if (traffic_light_http_server_) { traffic_light_http_server_->stop(); } @@ -832,6 +835,11 @@ void System::processPushedTrafficLightData(const nlohmann::json& di_data) { signal.timestamp = std::chrono::duration_cast( std::chrono::system_clock::now().time_since_epoch()).count(); + // 注入到 DataCollector 缓存,供主循环/检测器消费(替代轮询拉取) + if (dataCollector_) { + dataCollector_->injectTrafficLightSignals({ signal }); + } + if (ws_server_) { nlohmann::json messageJson; messageJson["type"] = "intersection_traffic_light_status"; diff --git a/src/core/System.h b/src/core/System.h index ff4ee52..046841c 100644 --- a/src/core/System.h +++ b/src/core/System.h @@ -16,6 +16,7 @@ #include "network/MessageTypes.h" #include "config/IntersectionConfig.h" #include "network/TrafficLightHttpServer.h" +#include "network/TrafficLightTcpServer.h" #include // 前向声明 @@ -98,6 +99,9 @@ private: // 新增: 红绿灯 HTTP 服务器 std::unique_ptr traffic_light_http_server_; std::thread traffic_light_http_server_thread_; + + // 新增: 红绿灯 TCP Server(对齐 tcp_server.py 的被动接收方式) + std::unique_ptr traffic_light_tcp_server_; // 路口配置 IntersectionConfig intersection_config_; diff --git a/src/network/TrafficLightTcpServer.cpp b/src/network/TrafficLightTcpServer.cpp new file mode 100644 index 0000000..9054f4b --- /dev/null +++ b/src/network/TrafficLightTcpServer.cpp @@ -0,0 +1,94 @@ +#include "network/TrafficLightTcpServer.h" +#include "utils/Logger.h" + +#include + +namespace network { + +using tcp = boost::asio::ip::tcp; + +TrafficLightTcpServer::TrafficLightTcpServer(uint16_t port, MessageHandler on_message) + : port_(port), on_message_(std::move(on_message)) {} + +TrafficLightTcpServer::~TrafficLightTcpServer() { + stop(); +} + +void TrafficLightTcpServer::start() { + if (running_.exchange(true)) { + return; + } + + thread_ = std::thread([this]() { + try { + run(); + } catch (const std::exception& e) { + Logger::error("TrafficLightTcpServer crashed: ", e.what()); + } + }); +} + +void TrafficLightTcpServer::stop() { + if (!running_.exchange(false)) { + return; + } + + try { + if (acceptor_) { + boost::system::error_code ec; + acceptor_->close(ec); + } + ioc_.stop(); + } catch (...) { + } + + if (thread_.joinable()) { + thread_.join(); + } +} + +void TrafficLightTcpServer::run() { + acceptor_ = std::make_unique(ioc_, tcp::endpoint(tcp::v4(), port_)); + Logger::info("Traffic light TCP server listening on 0.0.0.0:", port_); + + while (running_) { + boost::system::error_code ec; + tcp::socket socket(ioc_); + acceptor_->accept(socket, ec); + if (!running_) { + break; + } + if (ec) { + Logger::error("TrafficLightTcpServer accept error: ", ec.message()); + continue; + } + + try { + Logger::info("TrafficLightTcpServer connection from ", socket.remote_endpoint().address().to_string(), ":", socket.remote_endpoint().port()); + + std::string payload; + payload.resize(4096); + std::size_t n = socket.read_some(boost::asio::buffer(payload), ec); + if (ec && ec != boost::asio::error::eof) { + Logger::error("TrafficLightTcpServer read error: ", ec.message()); + } else { + payload.resize(n); + if (on_message_) { + on_message_(payload); + } + } + + // 回应(对齐 python 脚本行为) + const std::string response = "Hello from the server!"; + boost::asio::write(socket, boost::asio::buffer(response), ec); + } catch (const std::exception& e) { + Logger::error("TrafficLightTcpServer client handler error: ", e.what()); + } + + boost::system::error_code ec_shutdown; + socket.shutdown(tcp::socket::shutdown_both, ec_shutdown); + socket.close(ec_shutdown); + } +} + +} // namespace network diff --git a/src/network/TrafficLightTcpServer.h b/src/network/TrafficLightTcpServer.h new file mode 100644 index 0000000..be0a81f --- /dev/null +++ b/src/network/TrafficLightTcpServer.h @@ -0,0 +1,40 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +namespace network { + +// 简单 TCP Server:行为对齐 tcp_server.py(accept -> recv 一段 -> 回应 -> close) +class TrafficLightTcpServer { +public: + using MessageHandler = std::function; + + TrafficLightTcpServer(uint16_t port, MessageHandler on_message); + ~TrafficLightTcpServer(); + + TrafficLightTcpServer(const TrafficLightTcpServer&) = delete; + TrafficLightTcpServer& operator=(const TrafficLightTcpServer&) = delete; + + void start(); + void stop(); + +private: + void run(); + + uint16_t port_; + MessageHandler on_message_; + + boost::asio::io_context ioc_; + std::unique_ptr acceptor_; + + std::atomic running_{false}; + std::thread thread_; +}; + +} // namespace network diff --git a/system_config.json b/system_config.json new file mode 100644 index 0000000..cfcfcc8 --- /dev/null +++ b/system_config.json @@ -0,0 +1,113 @@ +{ + "airport": { + "name": "青岛胶东国际机场", + "iata": "TAO", + "icao": "ZSQD", + "reference_point": { + "latitude": 36.34807893, + "longitude": 120.08201044 + }, + "coordinate_points": [ + {"point": "T1", "longitude": 120.0868853, "latitude": 36.35496367}, + {"point": "T2", "longitude": 120.08502054, "latitude": 36.35448347}, + {"point": "T3", "longitude": 120.08341044, "latitude": 36.35406879}, + {"point": "T4", "longitude": 120.08558121, "latitude": 36.35305878}, + {"point": "T5", "longitude": 120.08400957, "latitude": 36.35265197}, + {"point": "T6", "longitude": 120.08649105, "latitude": 36.35074527}, + {"point": "T7", "longitude": 120.08562915, "latitude": 36.35052372}, + {"point": "T8", "longitude": 120.08676664, "latitude": 36.35004529}, + {"point": "T9", "longitude": 120.08520616, "latitude": 36.34964473}, + {"point": "T10", "longitude": 120.08710569, "latitude": 36.34917893}, + {"point": "T11", "longitude": 120.0873865, "latitude": 36.3509885}, + {"point": "T12", "longitude": 120.08603613, "latitude": 36.35190217}, + {"point": "T13", "longitude": 120.08509148, "latitude": 36.35041247} + ] + }, +"data_source": { + "position": { + "host": "10.32.38.3", + "port": 8090, + "aircraft_path": "/openApi/getCurrentFlightPositions", + "vehicle_path": "/openApi/getCurrentVehiclePositions", + "refresh_interval_ms": 500, + "auth": { + "username": "dianxin", + "password": "dianxin@123", + "auth_path": "/login", + "auth_required": true + }, + "timeout_ms": 5000, + "read_timeout_ms": 2000 + }, + "unmanned_vehicle": { + "host": "10.32.38.3", + "port": 8090, + "location_path": "/api/VehicleLocationInfo", + "status_path": "/api/VehicleStateInfo", + "command_path": "/api/VehicleCommandInfo", + "refresh_interval_ms": 500, + "auth": { + "username": "dianxin", + "password": "dianxin@123", + "auth_path": "/api/login", + "auth_required": false + }, + "timeout_ms": 5000, + "read_timeout_ms": 2000 + }, + "traffic_light": { + "host": "10.32.38.3", + "port": 8090, + "signal_path": "/getTrafficLightSignals", + "refresh_interval_ms": 500, + "auth": { + "username": "dianxin", + "password": "dianxin@123", + "auth_path": "/api/login", + "auth_required": false + }, + "timeout_ms": 5000, + "read_timeout_ms": 2000 + } +}, + "warning": { + "warning_interval_ms": 1000, + "log_interval_ms": 3000 + }, + "websocket": { + "port": 8010, + "max_connections": 100, + "ping_interval_ms": 30000, + "position_update": { + "aircraft_interval_ms": 300, + "vehicle_interval_ms": 500, + "traffic_light_interval_ms": 1000 + } + }, + "collision_detection": { + "update_interval_ms": 200, + "prediction": { + "time_window": 20.0, + "vehicle_size": 20.0, + "aircraft_size": 60.0, + "min_unmanned_speed": 1.0 + } + }, + "logging": { + "level": "info", + "file": "logs/system.log", + "max_size_mb": 10, + "max_files": 5, + "console_output": true + }, + "debug": { + "enable_mock_data": false, + "save_raw_data": false, + "profile_performance": false + }, + "traffic_light_server": { + "port": 8082, + "max_connections": 100 + }, + "simulated_mobile_light_target_intersection_id": "T2路口" +} diff --git a/tcp_server.py b/tcp_server.py new file mode 100644 index 0000000..3214527 --- /dev/null +++ b/tcp_server.py @@ -0,0 +1,34 @@ +import socket + +def tcp_server(): + #host = '127.0.0.1' # Localhost + host = '0.0.0.0' # Localhost + port = 8082 # Port to listen on + + server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + server_socket.bind((host, port)) + server_socket.listen(5) # Listen for up to 5 queued connections + + print(f"Server listening on {host}:{port}") + + while True: + client_socket, client_address = server_socket.accept() + print(f"Connection established with {client_address}") + + try: + # Receive data from the client + data = client_socket.recv(1024).decode('utf-8') + print(f"Received from client: {data}") + + # Send a response back to the client + response = "Hello from the server!" + client_socket.send(response.encode('utf-8')) + + except Exception as e: + print(f"Error handling client: {e}") + finally: + client_socket.close() + print(f"Connection with {client_address} closed.") + +if __name__ == "__main__": + tcp_server() \ No newline at end of file