轮询Siemens LOGO设备时触发System.IO.IOException问题求助
问题:读取Siemens LOGO! 24RCE的Modbus数据时连接被远程主机强制关闭
我刚接触Modbus和UWA,现在要开发应用读取**Siemens LOGO! 24RCE(型号6ED1052-1HB08-0BA0)**的输入1、输出1和输出2状态,设备已运行测试程序。当前代码如下:
// 其他引用包 using EasyModbus; using System.Net.Sockets; namespace AC_C_Demo { /// <summary> /// An empty page that can be used on its own or navigated to within a Frame. /// </summary> public sealed partial class MainPage : Page { private ModbusClient modbusClient; public MainPage() { this.InitializeComponent(); modbusClient = new ModbusClient("192.168.0.3", 502); // 替换为设备IP和端口 ReadModbusData_Click(); } private async void ReadModbusData_Click() { modbusClient.Connect(); while (true) { // 读取输入1 bool i1Value = modbusClient.ReadDiscreteInputs(0, 1)[0]; // 读取输出1 bool q1Value = modbusClient.ReadCoils(0, 1)[0]; // 读取输出2 bool q2Value = modbusClient.ReadCoils(1, 1)[0]; // 在TextBlocks中显示值 InputStatusTextBlock.Text = "I1: " + i1Value.ToString(); // Q1ValueTextBlock.Text = "Q1: " + q1Value.ToString(); // Q2ValueTextBlock.Text = "Q2: " + q2Value.ToString(); } } } }
执行到bool i1Value = modbusClient.ReadDiscreteInputs(0, 1)[0];时触发错误:
System.IO.IOException: 'Unable to write data to the transport connection: An existing connection was forcibly closed by the remote host.' SocketException: An existing connection was forcibly closed by the remote host
已确认设备和电脑同网段以太网连接,防火墙已关闭,换过多个Modbus包都出现相同问题。同时想了解有没有更优的实现方案。
解决方案
1. 修正Siemens LOGO!的Modbus地址映射
Siemens LOGO!的Modbus地址和标准Modbus地址存在起始偏移,不能直接用0作为起始地址:
- 离散输入(I点):LOGO!的I1对应Modbus离散输入地址
1(LOGO!的Modbus地址从1开始计数) - 线圈(Q点):LOGO!的Q1对应Modbus线圈地址
1,Q2对应2
修改读取地址的代码:
// 读取输入I1(对应Modbus离散输入地址1) bool i1Value = modbusClient.ReadDiscreteInputs(1, 1)[0]; // 读取输出Q1(对应Modbus线圈地址1) bool q1Value = modbusClient.ReadCoils(1, 1)[0]; // 读取输出Q2(对应Modbus线圈地址2) bool q2Value = modbusClient.ReadCoils(2, 1)[0];
2. 修复代码的异步与循环问题
- 当前
ReadModbusData_Click是async void但未使用await,无限循环会阻塞UI线程,频繁读写也会触发设备断开连接 - 加入延迟控制读取频率,用
await Task.Delay避免阻塞,同时确保UI更新在UI线程执行:
修改后的读取方法:
private async void ReadModbusData_Click() { try { modbusClient.Connect(); while (true) { // 读取数据 bool i1Value = modbusClient.ReadDiscreteInputs(1, 1)[0]; bool q1Value = modbusClient.ReadCoils(1, 1)[0]; bool q2Value = modbusClient.ReadCoils(2, 1)[0]; // 在UI线程更新显示 await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () => { InputStatusTextBlock.Text = $"I1: {i1Value}"; Q1ValueTextBlock.Text = $"Q1: {q1Value}"; Q2ValueTextBlock.Text = $"Q2: {q2Value}"; }); // 控制读取频率,每500ms读取一次 await Task.Delay(500); } } catch (Exception ex) { // 捕获异常并提示 await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () => { InputStatusTextBlock.Text = $"错误: {ex.Message}"; }); // 异常时断开连接 if (modbusClient.Connected) modbusClient.Disconnect(); } }
3. 验证设备的Modbus配置
- 确认LOGO!设备已启用Modbus TCP服务器:在LOGO! Soft Comfort软件的通信设置中,开启Modbus TCP,设置正确的IP和端口(默认502)
- 检查设备权限:确保允许外部设备读取离散输入和线圈
- 先用Modbus测试工具(如Modbus Poll)验证连接和地址正确性,再回到代码调试
4. 更优实现建议
- 使用异步Modbus客户端:选择支持异步API的Modbus库,避免同步调用阻塞UI
- 批量读取数据:一次性读取多个点位,减少网络交互次数:
// 一次性读取I1(1个点) bool[] inputValues = modbusClient.ReadDiscreteInputs(1, 1); // 一次性读取Q1-Q2(2个点) bool[] coilValues = modbusClient.ReadCoils(1, 2); bool q1Value = coilValues[0]; bool q2Value = coilValues[1]; - 添加自动重连机制:连接断开时自动尝试重新连接,提升稳定性
- 增加日志记录:记录Modbus交互细节,方便排查问题
内容的提问来源于stack exchange,提问作者GTurkistane
相关产品推荐
相关产品推荐

