修复bug

This commit is contained in:
sladro 2026-01-28 09:56:53 +08:00
parent 57a4682c87
commit 4bd984a540
9 changed files with 395 additions and 43 deletions

View File

@ -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 FetchContentCentOS 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)

View File

@ -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<TrafficLightSignal> DataCollector::getTrafficLightSignals() {
return trafficLightCache_;
}
void DataCollector::injectTrafficLightSignals(std::vector<TrafficLightSignal> signals) {
{
std::lock_guard<std::mutex> 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<TrafficLightSignal>& signals) {
if (!dataSource_) {

View File

@ -44,6 +44,8 @@ public:
std::vector<Aircraft> getAircraftData();
std::vector<Vehicle> getVehicleData();
std::vector<TrafficLightSignal> getTrafficLightSignals();
// TCP 推送模式下由外部注入红绿灯信号(替代轮询拉取)
void injectTrafficLightSignals(std::vector<TrafficLightSignal> signals);
bool fetchTrafficLightSignals(std::vector<TrafficLightSignal>& signals);
bool fetchUnmannedVehicleStatus(const std::string& vehicle_id, std::string& status);
bool fetchPositionData(); // 获取位置数据

View File

@ -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<network::TrafficLightHttpServer>(
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.pyaccept -> recv -> 响应 -> close
// 这里先写死监听端口 80820.0.0.0),用于你先在测试平台验证链路
traffic_light_tcp_server_ = std::make_unique<network::TrafficLightTcpServer>(
static_cast<uint16_t>(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<AirportBounds>("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::milliseconds>(
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";

View File

@ -16,6 +16,7 @@
#include "network/MessageTypes.h"
#include "config/IntersectionConfig.h"
#include "network/TrafficLightHttpServer.h"
#include "network/TrafficLightTcpServer.h"
#include <nlohmann/json_fwd.hpp>
// 前向声明
@ -98,6 +99,9 @@ private:
// 新增: 红绿灯 HTTP 服务器
std::unique_ptr<network::TrafficLightHttpServer> traffic_light_http_server_;
std::thread traffic_light_http_server_thread_;
// 新增: 红绿灯 TCP Server对齐 tcp_server.py 的被动接收方式)
std::unique_ptr<network::TrafficLightTcpServer> traffic_light_tcp_server_;
// 路口配置
IntersectionConfig intersection_config_;

View File

@ -0,0 +1,94 @@
#include "network/TrafficLightTcpServer.h"
#include "utils/Logger.h"
#include <boost/asio/ip/tcp.hpp>
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<tcp::acceptor>(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

View File

@ -0,0 +1,40 @@
#pragma once
#include <boost/asio.hpp>
#include <atomic>
#include <cstdint>
#include <functional>
#include <memory>
#include <string>
#include <thread>
namespace network {
// 简单 TCP Server行为对齐 tcp_server.pyaccept -> recv 一段 -> 回应 -> close
class TrafficLightTcpServer {
public:
using MessageHandler = std::function<void(const std::string& payload)>;
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<boost::asio::ip::tcp::acceptor> acceptor_;
std::atomic<bool> running_{false};
std::thread thread_;
};
} // namespace network

113
system_config.json Normal file
View File

@ -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路口"
}

34
tcp_server.py Normal file
View File

@ -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()