I am trying to use EasyModbusTCP v5.0 in my (fairly ambitious) project to connect to multiple slave devices and read/write values from/to them in a control loop as a Modbus master device. I'm writing the code in VisualBasic.NET. At present, I'm using your EasyModbusTCP Server Simulator v5.0 as my "slave device" under test before moving on to the real thing.
Problem
At the moment, I cannot get it to run for more than about 15-90 seconds continuously without throwing exceptions:
Exception 1:
System.IO.IOException: Unable to read data from the transport connection: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond. ---> System.Net.Sockets.SocketException: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond
at System.Net.Sockets.Socket.Receive(Byte[] buffer, Int32 offset, Int32 size, SocketFlags socketFlags)
at System.Net.Sockets.NetworkStream.Read(Byte[] buffer, Int32 offset, Int32 size)
--- End of inner exception stack trace ---
at System.Net.Sockets.NetworkStream.Read(Byte[] buffer, Int32 offset, Int32 size)
at EasyModbus.ModbusClient.ReadInputRegisters(Int32 startingAddress, Int32 quantity)
at RTModbusControl.EnergyCell.ReadMeasurements() in C:\Users\Scott\source\repos\RTModbusControl\RTModbusControl\EnergyCell.vb:line 66
Exception 2:
System.IO.IOException: Unable to read data from the transport connection: A blocking operation was interrupted by a call to WSACancelBlockingCall. ---> System.Net.Sockets.SocketException: A blocking operation was interrupted by a call to WSACancelBlockingCall
at System.Net.Sockets.Socket.Receive(Byte[] buffer, Int32 offset, Int32 size, SocketFlags socketFlags)
at System.Net.Sockets.NetworkStream.Read(Byte[] buffer, Int32 offset, Int32 size)
--- End of inner exception stack trace ---
at System.Net.Sockets.NetworkStream.Read(Byte[] buffer, Int32 offset, Int32 size)
at EasyModbus.ModbusClient.ReadInputRegisters(Int32 startingAddress, Int32 quantity)
at RTModbusControl.EnergyCell.ReadMeasurements() in C:\Users\Scott\source\repos\RTModbusControl\RTModbusControl\EnergyCell.vb:line 66
Code and Attempts to Fix
I have tried to slow the loop down (one calling timer event per 250 ms), and only execute one block of read or write calls at a time, but I can't seem to get it to work consistently. I am instantiating clients (one for each device) as:
...
connection.Client = New ModbusClient(ip, CType(port, Integer)) With {
.UnitIdentifier = CByte(id),
.ConnectionTimeout = 249
}
...
I then add this connection class instance to an EnergyCell class instance as CellConnection, which is what I use later. ip is a string containing the user-defined IP address of the device, which at present is set to the loopback (127.0.0.1), while port is set to another user-defined value (in this case, 502).
I am reading or writing single registers, one after another with (for example):
Public Sub ReadMeasurements()
Dim registerAddresses As Integer() = {1, 2, 3, 4, 5, 6, 7, 8, 9}
Dim wordResult As Integer() = {0}
Dim powerAngle As Double
For Each a In registerAddresses
If Not CellConnection.Client.Connected Then
CellConnection.Client.Connect(CellConnection.Client.IPAddress, CellConnection.Client.Port)
Working = True
Try
wordResult = CellConnection.Client.ReadInputRegisters(a - 1, 1)
Catch e As Exception
Console.WriteLine(e.ToString())
End Try
ElseIf CellConnection.Client.Connected Then
Working = True
Try
wordResult = CellConnection.Client.ReadInputRegisters(a - 1, 1)
Catch e As Exception
Console.WriteLine(e.ToString())
End Try
End If
Select Case a
Case 1
...
I proceed to perform some calculations on the measured values. There are also subroutines for writing values to the device registers and reading those values in the case of local control (i.e. if the device has a DSP connected to it). Each of them has an equal chance of throwing the exceptions, and it just seems to occur at random after some period of time. Everything works wonderfully until the exceptions start. Once that happens, no further communication occurs between my program and the Server Simulator and I cannot reconnect. I have tried using .Disconnect() and then .Connect() in the Catch block to no avail.
I read through all the discussions here (even those which were not pertinent to my issue) and noticed that this has come up before. You may notice that I am setting UnitIdentifier to a value other than zero (specifically, a value entered by the user). This is because one application of this software will be to connect to multiple simulated devices running in the same OpalRT server, which has only one IP address, but each device will have its ID (slave address) set uniquely. The software running on the server, RT-LAB, is capable of implementing Modbus and allows each device to have a distinct address (as per the specification for the protocol's ADU over TCP).
I have another form for testing the connection and Modbus function codes, and I can run as many tests as I'd like there, since they are single read/write calls with no automation; I have to press a button to read or write. This form works properly in RT-LAB as well, and seems to correctly address each device via the UnitIdentifier, reading or writing as commanded to the appropriate registers.
I have a feeling I'm either overworking the Server Simulator or I'm abusing the NetworkStream, but I'm not sure. To that end, I've also tried using function codes FC03, FC04, and FC16, which seem to work well (for at least 10 minutes at a time, no exceptions), but I'd really like to be able to update values one at a time instead of in bulk if possible. I'd appreciate any guidance or assistance you can provide!
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Somehow managed to get myself logged out prior to posting those two replies, and didn't notice. The gist of the problem was "helicopter parenting" the connection, and mistakes in the interpretation of signed/unsigned integers. I also started using the FC03, 04, and 16 functions.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Anonymous
Anonymous
-
2018-09-05
Post awaiting moderation.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Anonymous
Anonymous
-
2020-04-20
Post awaiting moderation.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Yes. Connections (and thus, clients) are cheap; abandon them at the earliest sign of trouble. That means using Try...Catch where you should toss the connection in the Catch block as basically the only action (don't try to resolve anything, it's useless and more effort than it's worth), abandoning it after any latency longer than you'd like, also after a malformed response, etc. Basically just constantly remake clients/connections (they're more or less one and the same) and everything works perfectly. From there you can assess what things you'd actually like to try to accommodate/fix, but start with just tossing everything at the slightest sign of trouble and you'll be encouraged by how well the results bear out. I know I was!
Hello!
I am trying to use EasyModbusTCP v5.0 in my (fairly ambitious) project to connect to multiple slave devices and read/write values from/to them in a control loop as a Modbus master device. I'm writing the code in VisualBasic.NET. At present, I'm using your EasyModbusTCP Server Simulator v5.0 as my "slave device" under test before moving on to the real thing.
Problem
At the moment, I cannot get it to run for more than about 15-90 seconds continuously without throwing exceptions:
Exception 1:
Exception 2:
Code and Attempts to Fix
I have tried to slow the loop down (one calling timer event per 250 ms), and only execute one block of read or write calls at a time, but I can't seem to get it to work consistently. I am instantiating clients (one for each device) as:
I then add this
connection
class instance to anEnergyCell
class instance asCellConnection
, which is what I use later.ip
is a string containing the user-defined IP address of the device, which at present is set to the loopback (127.0.0.1), whileport
is set to another user-defined value (in this case, 502).I am reading or writing single registers, one after another with (for example):
I proceed to perform some calculations on the measured values. There are also subroutines for writing values to the device registers and reading those values in the case of local control (i.e. if the device has a DSP connected to it). Each of them has an equal chance of throwing the exceptions, and it just seems to occur at random after some period of time. Everything works wonderfully until the exceptions start. Once that happens, no further communication occurs between my program and the Server Simulator and I cannot reconnect. I have tried using
.Disconnect()
and then.Connect()
in theCatch
block to no avail.I read through all the discussions here (even those which were not pertinent to my issue) and noticed that this has come up before. You may notice that I am setting
UnitIdentifier
to a value other than zero (specifically, a value entered by the user). This is because one application of this software will be to connect to multiple simulated devices running in the same OpalRT server, which has only one IP address, but each device will have its ID (slave address) set uniquely. The software running on the server, RT-LAB, is capable of implementing Modbus and allows each device to have a distinct address (as per the specification for the protocol's ADU over TCP).I have another form for testing the connection and Modbus function codes, and I can run as many tests as I'd like there, since they are single read/write calls with no automation; I have to press a button to read or write. This form works properly in RT-LAB as well, and seems to correctly address each device via the UnitIdentifier, reading or writing as commanded to the appropriate registers.
I have a feeling I'm either overworking the Server Simulator or I'm abusing the NetworkStream, but I'm not sure. To that end, I've also tried using function codes FC03, FC04, and FC16, which seem to work well (for at least 10 minutes at a time, no exceptions), but I'd really like to be able to update values one at a time instead of in bulk if possible. I'd appreciate any guidance or assistance you can provide!
I'm having the same issue. Any headway on this error?
Somehow managed to get myself logged out prior to posting those two replies, and didn't notice. The gist of the problem was "helicopter parenting" the connection, and mistakes in the interpretation of signed/unsigned integers. I also started using the FC03, 04, and 16 functions.
Hi Scott, I have the same issue. Did you resolve this ?
Yes. Connections (and thus, clients) are cheap; abandon them at the earliest sign of trouble. That means using
Try...Catch
where you should toss the connection in theCatch
block as basically the only action (don't try to resolve anything, it's useless and more effort than it's worth), abandoning it after any latency longer than you'd like, also after a malformed response, etc. Basically just constantly remake clients/connections (they're more or less one and the same) and everything works perfectly. From there you can assess what things you'd actually like to try to accommodate/fix, but start with just tossing everything at the slightest sign of trouble and you'll be encouraged by how well the results bear out. I know I was!You can see the full program here.