using S7.Net; using System; using System.IO; using System.Net; using System.Threading; using System.Threading.Tasks; namespace DeviceCommand.Base { public class S7Device : IS7Device { // 保持和你一致的连接参数命名属性 public string IPAddress { get; private set; } = "127.0.0.1"; public CpuType CpuType { get; private set; } = CpuType.S71200; public short Rack { get; private set; } = 0; public short Slot { get; private set; } = 1; public int SendTimeout { get; private set; } = 3000; public int ReceiveTimeout { get; private set; } = 3000; private Plc _plc; public Plc PlcContext => _plc; // S7.Net 的 Plc.IsConnected 属性内部会通过 Socket 状态进行判断 public bool IsConnected => _plc?.IsConnected ?? false; // 统一线程锁 protected readonly SemaphoreSlim _commLock = new(1, 1); public S7Device() { // 初始化默认配置 _plc = new Plc(CpuType, IPAddress, Rack, Slot); } /// /// 设备参数配置(符合你的命名风格) /// public void ConfigureDevice(string ipAddress, CpuType cpuType, short rack = 0, short slot = 1, int sendTimeout = 3000, int receiveTimeout = 3000) { IPAddress = ipAddress; CpuType = cpuType; Rack = rack; Slot = slot; SendTimeout = sendTimeout; ReceiveTimeout = receiveTimeout; } public virtual async Task ConnectAsync(CancellationToken ct = default) { await _commLock.WaitAsync(ct); try { // 如果已经连接,检查当前的 IP 和 CPU 类型是否一致,一致则直接复用 if (_plc != null && _plc.IsConnected) { if (_plc.IP == IPAddress && _plc.CPU == CpuType && _plc.Rack == Rack && _plc.Slot == Slot) return true; } // 修复:释放并彻底清空旧连接实例 if (_plc != null) { _plc.Close(); } // 重新实例化 Plc 对象并配置超时 _plc = new Plc(CpuType, IPAddress, Rack, Slot) { ReadTimeout = ReceiveTimeout, WriteTimeout = SendTimeout }; // 部分版本 S7.Net 的 OpenAsync 本身不接受 CancellationToken,我们通过 WaitAsync 实现超时 await _plc.OpenAsync().WaitAsync(TimeSpan.FromMilliseconds(SendTimeout), ct); return _plc.IsConnected; } catch { return false; } finally { _commLock.Release(); } } public virtual void Close() { if (_plc != null && _plc.IsConnected) _plc.Close(); } public async Task WriteAsync(string address, object value, CancellationToken ct = default) { await _commLock.WaitAsync(ct); try { if (!IsConnected) throw new InvalidOperationException("PLC未连接。"); await _plc.WriteAsync(address, value) .WaitAsync(TimeSpan.FromMilliseconds(SendTimeout), ct); } finally { _commLock.Release(); } } public async Task ReadAsync(string address, CancellationToken ct = default) { await _commLock.WaitAsync(ct); try { if (!IsConnected) throw new InvalidOperationException("PLC未连接。"); return await _plc.ReadAsync(address) .WaitAsync(TimeSpan.FromMilliseconds(ReceiveTimeout), ct); } finally { _commLock.Release(); } } public async Task ReadAsync(string address, CancellationToken ct = default) { var result = await ReadAsync(address, ct); return (T)result; } public async Task ReadBytesAsync(DataType dataType, int db, int startByteAdr, int count, CancellationToken ct = default) { await _commLock.WaitAsync(ct); try { if (!IsConnected) throw new InvalidOperationException("PLC未连接。"); return await _plc.ReadBytesAsync(dataType, db, startByteAdr, count) .WaitAsync(TimeSpan.FromMilliseconds(ReceiveTimeout), ct); } finally { _commLock.Release(); } } public async Task WriteBytesAsync(DataType dataType, int db, int startByteAdr, byte[] value, CancellationToken ct = default) { await _commLock.WaitAsync(ct); try { if (!IsConnected) throw new InvalidOperationException("PLC未连接。"); await _plc.WriteBytesAsync(dataType, db, startByteAdr, value) .WaitAsync(TimeSpan.FromMilliseconds(SendTimeout), ct); } finally { _commLock.Release(); } } public void Dispose() { _plc?.Close(); _commLock?.Dispose(); } } }