using System.Collections.Concurrent; using System.Linq; using System.Net.NetworkInformation; 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(); /// /// 连接监控定时器 /// private System.Threading.Timer? _connectionMonitorTimer; /// /// 构造函数 /// /// 实例配置 /// 日志记录器 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; // 启动连接监控定时器(每5秒检查一次) _connectionMonitorTimer = new System.Threading.Timer( _ => MonitorConnections(), null, TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(5)); _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 { // 停止连接监控定时器 _connectionMonitorTimer?.Dispose(); _connectionMonitorTimer = null; 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 object GetFullState() { lock (_lock) { // 更新客户端连接数 State.ClientCount = _clients.Count; State.Clients = _clients.Values.ToList(); return new { InstanceId = State.InstanceId, Name = Config.Name, PLCType = Config.PLCType.ToString(), Port = Config.Port, Status = State.Status.ToString(), ClientCount = State.ClientCount, TotalRequests = State.TotalRequests, StartTime = State.StartTime, LastActivityTime = State.LastActivityTime, Clients = 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, "从服务器同步数据时发生警告"); } } /// /// 监控客户端连接(通过检查TCP连接) /// private void MonitorConnections() { try { if (_server == null || State.Status != InstanceStatus.Running) return; var currentConnections = new HashSet(); var now = DateTime.Now; // 获取当前所有TCP连接 var tcpConnections = IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpConnections(); // 筛选出监听端口的已建立连接 var connectionsOnPort = tcpConnections.Where(c => c.LocalEndPoint.Port == Config.Port && c.State == TcpState.Established); foreach (var connection in connectionsOnPort) { var endPoint = connection.RemoteEndPoint.ToString(); currentConnections.Add(endPoint); // 检查是否是新连接 if (!_clients.ContainsKey(endPoint)) { var clientConnection = new S7ClientConnection { ClientId = endPoint, RemoteEndPoint = endPoint, ConnectedTime = now, LastActivityTime = now }; _clients[endPoint] = clientConnection; _logger.LogInformation("实例 {InstanceId} 检测到新客户端连接: {EndPoint}, 当前连接数: {Count}", Config.Id, endPoint, _clients.Count); } else { // 更新活动时间 _clients[endPoint].LastActivityTime = now; } } // 移除断开的连接 var disconnectedClients = _clients.Keys.Where(k => !currentConnections.Contains(k)).ToList(); foreach (var disconnected in disconnectedClients) { if (_clients.TryRemove(disconnected, out var client)) { _logger.LogInformation("实例 {InstanceId} 客户端断开: {EndPoint}, 当前连接数: {Count}", Config.Id, disconnected, _clients.Count); } } // 更新状态 State.ClientCount = _clients.Count; State.LastActivityTime = now; } 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; } } } }