using System.Collections.Concurrent;
using HslCommunication;
using HslCommunication.Profinet.Siemens;
using HslCommunication.Reflection;
using Microsoft.Extensions.Logging;
using WIDESEAWCS_S7Simulator.Core.Entities;
using WIDESEAWCS_S7Simulator.Core.Enums;
using WIDESEAWCS_S7Simulator.Core.Interfaces;
using WIDESEAWCS_S7Simulator.Core.Memory;
namespace WIDESEAWCS_S7Simulator.Core.Server
{
///
/// S7服务器实例实现
/// 使用HSL Communication库实现S7 PLC仿真服务器
///
public class S7ServerInstance : IS7ServerInstance
{
private readonly ILogger _logger;
private readonly object _lock = new();
private SiemensS7Server? _server;
private bool _disposed;
///
public InstanceConfig Config { get; }
///
public InstanceState State { get; private set; }
///
public IMemoryStore MemoryStore { get; }
///
/// 客户端连接追踪
///
private readonly ConcurrentDictionary _clients = new();
///
/// 构造函数
///
/// 实例配置
/// 日志记录器
public S7ServerInstance(InstanceConfig config, ILogger logger)
{
Config = config ?? throw new ArgumentNullException(nameof(config));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
// 初始化内存存储
MemoryStore = new MemoryStore(config.MemoryConfig);
// 初始化状态
State = new InstanceState
{
InstanceId = config.Id,
Status = InstanceStatus.Stopped,
ClientCount = 0,
TotalRequests = 0
};
_logger.LogInformation("S7服务器实例 {InstanceId} ({InstanceName}) 已创建,PLC类型: {PLCType}, 端口: {Port}",
config.Id, config.Name, config.PLCType, config.Port);
}
///
public bool Start()
{
lock (_lock)
{
if (_disposed)
{
_logger.LogError("无法启动已释放的实例 {InstanceId}", Config.Id);
return false;
}
if (State.Status == InstanceStatus.Running)
{
_logger.LogWarning("实例 {InstanceId} 已在运行中", Config.Id);
return true;
}
try
{
// 创建S7服务器
_server = new SiemensS7Server();
// 设置激活码
if (!string.IsNullOrWhiteSpace(Config.ActivationKey))
{
HslCommunication.Authorization.SetAuthorizationCode(Config.ActivationKey);
_logger.LogDebug("已设置激活码");
}
// 初始化DB块(根据配置)
InitializeDbBlocks();
// 从MemoryStore同步初始数据到服务器
SynchronizeMemoryToServer();
// 启动服务器
try
{
_server.ServerStart(Config.Port);
}
catch (Exception ex)
{
_logger.LogError(ex, "启动S7服务器失败");
State.Status = InstanceStatus.Error;
State.ErrorMessage = ex.Message;
return false;
}
// 更新状态
State.Status = InstanceStatus.Running;
State.StartTime = DateTime.Now;
State.ErrorMessage = null;
_logger.LogInformation("S7服务器实例 {InstanceId} 已成功启动,监听端口: {Port}", Config.Id, Config.Port);
return true;
}
catch (Exception ex)
{
_logger.LogError(ex, "启动S7服务器实例 {InstanceId} 时发生异常", Config.Id);
State.Status = InstanceStatus.Error;
State.ErrorMessage = ex.Message;
return false;
}
}
}
///
public void Stop()
{
lock (_lock)
{
if (_disposed || State.Status == InstanceStatus.Stopped)
{
return;
}
try
{
if (_server != null)
{
// 停止前同步服务器数据到MemoryStore
SynchronizeServerToMemory();
_server.ServerClose();
_server = null;
}
// 清空客户端连接
_clients.Clear();
// 更新状态
State.Status = InstanceStatus.Stopped;
State.ClientCount = 0;
State.StartTime = null;
_logger.LogInformation("S7服务器实例 {InstanceId} 已停止", Config.Id);
}
catch (Exception ex)
{
_logger.LogError(ex, "停止S7服务器实例 {InstanceId} 时发生异常", Config.Id);
State.Status = InstanceStatus.Error;
State.ErrorMessage = ex.Message;
}
}
}
///
public bool Restart()
{
Stop();
return Start();
}
///
public InstanceState GetState()
{
lock (_lock)
{
// 更新客户端连接数
State.ClientCount = _clients.Count;
State.Clients = _clients.Values.ToList();
// 返回状态副本
return new InstanceState
{
InstanceId = State.InstanceId,
Status = State.Status,
ClientCount = State.ClientCount,
TotalRequests = State.TotalRequests,
StartTime = State.StartTime,
LastActivityTime = State.LastActivityTime,
Clients = new List(State.Clients),
ErrorMessage = State.ErrorMessage
};
}
}
///
public void ClearMemory()
{
lock (_lock)
{
MemoryStore.Clear();
// 同时清空服务器内部数据
if (_server != null && State.Status == InstanceStatus.Running)
{
// 清空各内存区域
for (int i = 0; i < 100; i++)
{
_server.Write($"M{i}", (byte)0);
_server.Write($"I{i}", (byte)0);
_server.Write($"Q{i}", (byte)0);
}
// 清空DB块
for (ushort db = 1; db <= Config.MemoryConfig.DBBlockCount; db++)
{
for (int i = 0; i < 10; i++)
{
_server.Write($"DB{db}.DBD{i}", (byte)0);
}
}
}
_logger.LogInformation("实例 {InstanceId} 内存已清空", Config.Id);
}
}
///
public Dictionary ExportMemory()
{
lock (_lock)
{
// 先同步服务器数据到MemoryStore
if (_server != null && State.Status == InstanceStatus.Running)
{
SynchronizeServerToMemory();
}
return MemoryStore.Export();
}
}
///
public void ImportMemory(Dictionary data)
{
lock (_lock)
{
MemoryStore.Import(data);
// 同步到服务器
if (_server != null && State.Status == InstanceStatus.Running)
{
SynchronizeMemoryToServer();
}
_logger.LogInformation("实例 {InstanceId} 内存数据已导入", Config.Id);
}
}
///
/// 初始化DB块
///
private void InitializeDbBlocks()
{
if (_server == null)
return;
try
{
// 根据配置添加DB块
for (ushort i = 1; i <= Config.MemoryConfig.DBBlockCount; i++)
{
_server.AddDbBlock(i, Config.MemoryConfig.DBBlockSize);
_logger.LogDebug("已添加DB块: DB{DbNumber}, 大小: {Size}", i, Config.MemoryConfig.DBBlockSize);
}
}
catch (Exception ex)
{
_logger.LogWarning(ex, "初始化DB块时发生警告");
}
}
///
/// 从MemoryStore同步数据到服务器
///
private void SynchronizeMemoryToServer()
{
if (_server == null)
return;
try
{
var data = MemoryStore.Export();
// 同步M区
if (data.ContainsKey("M"))
{
var mBytes = data["M"];
for (int i = 0; i < Math.Min(mBytes.Length, Config.MemoryConfig.MRegionSize); i++)
{
_server.Write($"M{i}", mBytes[i]);
}
}
// 同步I区
if (data.ContainsKey("I"))
{
var iBytes = data["I"];
for (int i = 0; i < Math.Min(iBytes.Length, Config.MemoryConfig.IRegionSize); i++)
{
_server.Write($"I{i}", iBytes[i]);
}
}
// 同步Q区
if (data.ContainsKey("Q"))
{
var qBytes = data["Q"];
for (int i = 0; i < Math.Min(qBytes.Length, Config.MemoryConfig.QRegionSize); i++)
{
_server.Write($"Q{i}", qBytes[i]);
}
}
// 同步DB区
if (data.ContainsKey("DB"))
{
var dbBytes = data["DB"];
int offset = 0;
for (ushort db = 1; db <= Config.MemoryConfig.DBBlockCount; db++)
{
int blockSize = Math.Min(Config.MemoryConfig.DBBlockSize, dbBytes.Length - offset);
for (int i = 0; i < blockSize; i++)
{
_server.Write($"DB{db}.DBD{i}", dbBytes[offset + i]);
}
offset += Config.MemoryConfig.DBBlockSize;
}
}
_logger.LogDebug("已将MemoryStore数据同步到S7服务器");
}
catch (Exception ex)
{
_logger.LogWarning(ex, "同步数据到服务器时发生警告");
}
}
///
/// 从服务器同步数据到MemoryStore
///
private void SynchronizeServerToMemory()
{
if (_server == null)
return;
try
{
var data = new Dictionary();
// 读取M区
var mResult = _server.Read("M0", (ushort)Config.MemoryConfig.MRegionSize);
if (mResult.IsSuccess)
{
data["M"] = mResult.Content;
}
// 读取I区
var iResult = _server.Read("I0", (ushort)Config.MemoryConfig.IRegionSize);
if (iResult.IsSuccess)
{
data["I"] = iResult.Content;
}
// 读取Q区
var qResult = _server.Read("Q0", (ushort)Config.MemoryConfig.QRegionSize);
if (qResult.IsSuccess)
{
data["Q"] = qResult.Content;
}
// 读取DB区
var dbBytes = new List();
for (ushort db = 1; db <= Config.MemoryConfig.DBBlockCount; db++)
{
var dbResult = _server.Read($"DB{db}.DBD0", (ushort)Config.MemoryConfig.DBBlockSize);
if (dbResult.IsSuccess)
{
dbBytes.AddRange(dbResult.Content);
}
}
data["DB"] = dbBytes.ToArray();
// 导入到MemoryStore
MemoryStore.Import(data);
_logger.LogDebug("已将S7服务器数据同步到MemoryStore");
}
catch (Exception ex)
{
_logger.LogWarning(ex, "从服务器同步数据时发生警告");
}
}
///
/// 增加请求计数并更新活动时间
///
private void IncrementRequestCount()
{
State.TotalRequests++;
State.LastActivityTime = DateTime.Now;
}
///
/// 释放资源
///
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
///
/// 释放资源
///
/// 是否正在释放托管资源
protected virtual void Dispose(bool disposing)
{
if (!_disposed)
{
if (disposing)
{
Stop();
MemoryStore?.Dispose();
}
_disposed = true;
}
}
}
}