V0.28.2.250618_alpha:修复了运行仿真第二次会导致崩溃的问题

This commit is contained in:
jinchao 2025-06-18 17:13:19 +08:00
parent 346b34ee40
commit 9c3326eeda
6 changed files with 341 additions and 38 deletions

Binary file not shown.

View File

@ -3,7 +3,13 @@
SystemControl::~SystemControl()
{
//注销引擎控制发布者
if (m_EngineControlWriter != nullptr) {
cleanup();
}
}
void SystemControl::cleanup()
{
TopicManager::Instance()->unregisterPublisher("XNSim::XNSimControl::XNRuntimeControl");
m_EngineControlWriter = nullptr;
}

View File

@ -17,6 +17,8 @@ public:
void Resume();
void Stop();
void cleanup();
private:
XNDataWriter *m_EngineControlWriter;
};

View File

@ -56,8 +56,6 @@ public:
->delete_participant(instance->m_Participant); // 删除参与者
instance->m_Participant = nullptr; // 设置参与者为空
}
delete instance; // 删除单例
instance = nullptr; // 设置单例为空
}
}

View File

@ -21,6 +21,7 @@ bool g_modelInfoMonitorStarted = false;
SystemControl *systemControl = nullptr;
bool g_systemControlStarted = false;
std::unordered_map<std::string, DataInjectThreadPtr> g_dataInjectThreads;
CSVDataInjectThread *g_csvDataInjectThread = nullptr;
DataCollect *g_dataCollect = nullptr;
@ -277,24 +278,6 @@ void XN_StopMonitorModelInfo()
}
}
// 清理函数实现
void XN_Cleanup()
{
if (g_initialized) {
// 停止并清理系统信息监控
if (g_systemInfoMonitorStarted) {
XN_StopMonitorSystemInfo();
}
// 停止并清理模型信息监控
if (g_modelInfoMonitorStarted) {
XN_StopMonitorModelInfo();
}
// 清理DDS参与者
TopicManager::cleanupParticipant();
g_initialized = false;
}
}
int XN_InitializeEngineControl(char *errorMsg, int errorMsgSize)
{
if (g_systemControlStarted) {
@ -360,6 +343,16 @@ void XN_StopEngine(char *errorMsg, int errorMsgSize)
systemControl->Stop();
}
void XN_CleanupEngineControl()
{
if (g_systemControlStarted) {
systemControl->cleanup();
delete systemControl;
systemControl = nullptr;
g_systemControlStarted = false;
}
}
int XN_StartDataMonitor(const char *structName, const int structNameLen, char *errorMsg,
int errorMsgSize)
{
@ -517,8 +510,6 @@ int XN_InjectDataInterface(const char *structName, const int structNameLen,
return 0;
}
std::unordered_map<std::string, DataInjectThreadPtr> g_dataInjectThreads;
int XN_StartInjectContinuous(const char *structName, const int structNameLen,
const char *interfaceNameAndData, const int interfaceNameAndDataLen,
double frequency, char *infoMsg, int infoMsgSize)
@ -585,12 +576,21 @@ int XN_StopInjectContinuous(const char *structName, const int structNameLen, cha
return 0;
}
void XN_CleanupInjectContinuous()
{
for (auto &it : g_dataInjectThreads) {
if (it.second) {
it.second->stop();
it.second.reset();
it.second = nullptr;
}
}
g_dataInjectThreads.clear();
}
// 从csv文件中注入数据接口
int XNMONITORSERVER_EXPORT XN_InjectDataInterfaceFromCsv(const char *injectDataInfo,
const int injectDataInfoLen,
const char *csvFilePath,
const int csvFilePathLen, char *infoMsg,
int infoMsgSize)
int XN_InjectDataInterfaceFromCsv(const char *injectDataInfo, const int injectDataInfoLen,
const char *csvFilePath, const int csvFilePathLen, char *infoMsg,
int infoMsgSize)
{
if (!g_initialized) {
if (infoMsg && infoMsgSize > 0) {
@ -724,10 +724,17 @@ int XN_StopCsvDataInject(char *infoMsg, int infoMsgSize)
return 0;
}
int XNMONITORSERVER_EXPORT XN_StartCollectData(const char *CollectDataInfo,
const int CollectDataInfoLen,
const char *dcsFilePath, const int dcsFilePathLen,
char *infoMsg, int infoMsgSize)
void XN_CleanupCsvDataInject()
{
if (g_csvDataInjectThread != nullptr) {
g_csvDataInjectThread->stop();
delete g_csvDataInjectThread;
g_csvDataInjectThread = nullptr;
}
}
int XN_StartCollectData(const char *CollectDataInfo, const int CollectDataInfoLen,
const char *dcsFilePath, const int dcsFilePathLen, char *infoMsg,
int infoMsgSize)
{
if (!g_initialized) {
if (infoMsg && infoMsgSize > 0) {
@ -807,7 +814,7 @@ int XNMONITORSERVER_EXPORT XN_StartCollectData(const char *CollectDataInfo,
return 0;
}
int XNMONITORSERVER_EXPORT XN_GetCollectDataStatus(char *infoMsg, int infoMsgSize)
int XN_GetCollectDataStatus(char *infoMsg, int infoMsgSize)
{
if (!g_initialized) {
if (infoMsg && infoMsgSize > 0) {
@ -828,7 +835,7 @@ int XNMONITORSERVER_EXPORT XN_GetCollectDataStatus(char *infoMsg, int infoMsgSiz
return g_dataCollect->isRunning() ? 1 : 0;
}
int XNMONITORSERVER_EXPORT XN_StopCollectData(char *infoMsg, int infoMsgSize)
int XN_StopCollectData(char *infoMsg, int infoMsgSize)
{
if (!g_initialized) {
if (infoMsg && infoMsgSize > 0) {
@ -859,4 +866,41 @@ int XNMONITORSERVER_EXPORT XN_StopCollectData(char *infoMsg, int infoMsgSize)
}
return 0;
}
void XN_CleanupDataCollect()
{
if (g_dataCollect != nullptr) {
g_dataCollect->stop();
delete g_dataCollect;
g_dataCollect = nullptr;
}
}
// 清理函数实现
void XN_Cleanup()
{
if (g_initialized) {
// 停止并清理系统信息监控
if (g_systemInfoMonitorStarted) {
XN_StopMonitorSystemInfo();
}
// 停止并清理模型信息监控
if (g_modelInfoMonitorStarted) {
XN_StopMonitorModelInfo();
}
// 停止并清理引擎控制
if (g_systemControlStarted) {
XN_CleanupEngineControl();
}
// 停止并清理数据采集
XN_CleanupDataCollect();
// 停止并清理CSV数据注入
XN_CleanupCsvDataInject();
// 停止并清理数据注入
XN_CleanupInjectContinuous();
// 清理DDS参与者
TopicManager::cleanupParticipant();
g_initialized = false;
}
}

View File

@ -1,11 +1,19 @@
/**
* @class NetworkMonitor
* @description 网络监控组件用于监控系统网络状态
* @description 网络监控组件用于监控系统网络状态和UDP数据抓包
*/
class NetworkMonitor extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
this.state = {
ip: '127.0.0.1',
port: 54321,
isMonitoring: false,
data: [],
timer: null,
statusMsg: '',
};
}
connectedCallback() {
@ -13,23 +21,268 @@ class NetworkMonitor extends HTMLElement {
this.initialize();
}
disconnectedCallback() {
if (this.state.timer) {
clearInterval(this.state.timer);
}
}
render() {
this.shadowRoot.innerHTML = `
<style>
:host {
display: block;
font-family: 'Segoe UI', 'PingFang SC', Arial, sans-serif;
background: #f4f6fa;
border-radius: 12px;
box-shadow: 0 2px 12px rgba(0,0,0,0.07);
padding: 24px 20px 20px 20px;
max-width: 600px;
}
.form-row {
display: flex;
align-items: center;
gap: 16px;
margin-bottom: 18px;
}
label {
font-size: 15px;
color: #333;
}
input[type="text"], input[type="number"] {
border: 1px solid #d0d7de;
border-radius: 6px;
padding: 6px 12px;
font-size: 15px;
outline: none;
transition: border 0.2s;
background: #fff;
margin-left: 4px;
}
input[type="text"]:focus, input[type="number"]:focus {
border: 1.5px solid #409eff;
}
.status {
display: flex;
align-items: center;
background: #eaf6ff;
color: #1976d2;
border-radius: 8px;
padding: 8px 14px;
margin-bottom: 16px;
font-size: 15px;
font-weight: 500;
box-shadow: 0 1px 4px rgba(64,158,255,0.07);
}
.status::before {
content: '\u26A1';
margin-right: 8px;
font-size: 18px;
}
button {
border: none;
border-radius: 6px;
padding: 7px 20px;
font-size: 15px;
cursor: pointer;
transition: background 0.2s, box-shadow 0.2s;
box-shadow: 0 1px 4px rgba(64,158,255,0.07);
}
#startBtn {
background: linear-gradient(90deg, #409eff 60%, #66b1ff 100%);
color: #fff;
font-weight: 600;
}
#startBtn:hover {
background: linear-gradient(90deg, #1976d2 60%, #409eff 100%);
}
#stopBtn {
background: #fff0f0;
color: #e53935;
font-weight: 600;
border: 1px solid #ffcdd2;
}
#stopBtn:hover {
background: #ffcdd2;
}
.monitor-status {
margin-bottom: 14px;
font-size: 15px;
color: #666;
}
.monitor-status span {
font-weight: bold;
color: #43a047;
}
.monitor-status span.stopped {
color: #e53935;
}
.data-list {
max-height: 340px;
overflow-y: auto;
background: #fff;
border-radius: 10px;
border: 1px solid #e0e3e7;
padding: 10px 0 10px 0;
box-shadow: 0 1px 6px rgba(0,0,0,0.04);
}
.data-item {
background: #f8fafc;
border-radius: 8px;
margin: 10px 16px;
padding: 10px 14px 8px 14px;
box-shadow: 0 1px 3px rgba(64,158,255,0.04);
border-left: 4px solid #409eff;
font-size: 14px;
transition: box-shadow 0.2s;
}
.data-item:hover {
box-shadow: 0 2px 8px rgba(64,158,255,0.13);
}
.data-item b {
color: #1976d2;
}
.data-item pre {
background: #f3f7fa;
border-radius: 4px;
padding: 4px 6px;
margin: 2px 0 0 0;
font-size: 13px;
color: #333;
}
.nodata {
color: #bbb;
text-align: center;
padding: 30px 0;
}
</style>
<div></div>
<div class="status">${this.state.statusMsg}</div>
<div class="form-row">
<label>IP: <input type="text" id="ip" value="${this.state.ip}" /></label>
<label>端口: <input type="number" id="port" value="${this.state.port}" min="1024" max="65535" /></label>
<button id="startBtn">开始抓包</button>
<button id="stopBtn">停止抓包</button>
</div>
<div class="monitor-status">抓包状态<span id="monitorStatus" class="${this.state.isMonitoring ? '' : 'stopped'}">${this.state.isMonitoring ? '运行中' : '已停止'}</span></div>
<div class="data-list" id="dataList"></div>
`;
this.shadowRoot.getElementById('startBtn').onclick = () => this.startMonitor();
this.shadowRoot.getElementById('stopBtn').onclick = () => this.stopMonitor();
this.shadowRoot.getElementById('ip').onchange = (e) => {
this.state.ip = e.target.value;
};
this.shadowRoot.getElementById('port').onchange = (e) => {
this.state.port = parseInt(e.target.value, 10);
};
this.renderDataList();
}
renderDataList() {
const dataList = this.shadowRoot.getElementById('dataList');
if (!dataList) return;
if (!this.state.data.length) {
dataList.innerHTML = '<div class="nodata">暂无数据</div>';
return;
}
dataList.innerHTML = this.state.data.map(item => `
<div class="data-item">
<div><b>时间:</b> ${new Date(item.timestamp).toLocaleString()}</div>
<div><b>来源:</b> ${item.source}</div>
<div><b>内容:</b> <pre>${typeof item.data === 'object' ? JSON.stringify(item.data, null, 2) : item.data}</pre></div>
</div>
`).join('');
}
setStatus(msg) {
this.state.statusMsg = msg;
this.render();
}
async startMonitor() {
this.setStatus('正在启动UDP抓包...');
try {
const res = await fetch('/api/udp-monitor/start', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ ip: this.state.ip, port: this.state.port })
});
const data = await res.json();
if (data.success) {
this.state.isMonitoring = true;
this.setStatus(data.message || 'UDP抓包已启动');
this.startPolling();
} else {
this.state.isMonitoring = false;
this.setStatus(data.error || '启动失败');
}
} catch (e) {
this.state.isMonitoring = false;
this.setStatus('启动UDP抓包失败: ' + e.message);
}
this.render();
}
async stopMonitor() {
this.setStatus('正在停止UDP抓包...');
try {
const res = await fetch('/api/udp-monitor/stop', { method: 'POST' });
const data = await res.json();
this.state.isMonitoring = false;
this.setStatus(data.message || 'UDP抓包已停止');
if (this.state.timer) {
clearInterval(this.state.timer);
this.state.timer = null;
}
} catch (e) {
this.setStatus('停止UDP抓包失败: ' + e.message);
}
this.render();
}
startPolling() {
if (this.state.timer) clearInterval(this.state.timer);
this.state.timer = setInterval(() => this.fetchData(), 1000);
}
async fetchData() {
if (!this.state.isMonitoring) return;
try {
const res = await fetch('/api/udp-monitor/data');
const data = await res.json();
if (data.success) {
if (Array.isArray(data.data) && data.data.length > 0) {
this.state.data = this.state.data.concat(data.data);
// 最多只保留1000条
if (this.state.data.length > 1000) {
this.state.data = this.state.data.slice(-1000);
}
this.renderDataList();
}
this.state.isMonitoring = data.isMonitoring;
this.shadowRoot.getElementById('monitorStatus').textContent = data.isMonitoring ? '运行中' : '已停止';
}
} catch (e) {
this.setStatus('获取UDP数据失败: ' + e.message);
}
}
initialize() {
console.log('网络监控组件已初始化');
this.setStatus('请设置IP和端口后点击开始抓包');
// 检查当前监控状态
fetch('/api/udp-monitor/status').then(res => res.json()).then(data => {
if (data.success && data.isMonitoring) {
this.state.isMonitoring = true;
this.state.ip = data.ip || this.state.ip;
this.state.port = data.port || this.state.port;
this.setStatus('UDP抓包已在运行');
this.startPolling();
this.render();
}
});
}
reactivate() {
console.log('网络监控组件已重新激活');
this.initialize();
}
}