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;
}
}
}
}