I'm trying to interact with an ABB 595 over modbus/tcp.
It basically works fine, but under some load I sometimes get a 'null' object back. This happens after a couple of hunderd to thousand loops.
in these cases the connection remains connected and the null object comes after the request almost imediately back (definately not a after the timeout). The network is stable, ping-response-time is short and does not change much (no relationship to the 'null' objects)
In my understanding I should get either a valid object - or an exception back...?
public class Plc {
static TCPMasterConnection con = null; //the connection
public synchronized static ModbusResponse modbus(ModbusRequest req) throws Exception {
ModbusResponse res=null;
// connect to PLC if never done so far
if (con==null) {
con = new TCPMasterConnection(InetAddress.getByName("10.0.0.221"));
con.setPort(Modbus.DEFAULT_PORT);
con.connect(); // would automatically happen
con.setTimeout(1000);
}
// Prepare the transaction
ModbusTCPTransaction trans = new ModbusTCPTransaction(con); //the Modbus transaction
trans.setRequest(req);
trans.setRetries(10);
trans.setCheckingValidity(true); // ???
// trans.setReconnecting(true); // ???
// execute the transaction
trans.execute();
// get the response
res = trans.getResponse();
System.out.println("...read "+ (res==null ? "NULL!?" : res.getHexMessage()));
return res; // this is _sometimes_ null...
} // modbus
I'm calling that from several small methods to get the desired datatype:
public static int readRegister(int startReg) throws Exception {
ReadMultipleRegistersRequest req = new ReadMultipleRegistersRequest(startReg, 1);
ReadMultipleRegistersResponse res = (ReadMultipleRegistersResponse)modbus(req);
return res.getRegister(0).getValue();
}
single calls work perfectly. I found the problem by 'torturing' it:
public static void main(String[] args) {
final int reg = 0;
final int loopRegStart = 0;
final int loopRegEnd = loopRegStart + 10000;
int r=0;
try {
for (int i=loopRegStart; i<(loopRegEnd); i++) {
r = readRegister(i);
if (r!=0) System.out.println(i + " = "+r);
};
con.close();
} catch (Exception ex) { ex.printStackTrace(); }
}//main
the null-object may be returned in the first iterations or after some thousand calls....
Is this a lack of my understanding, the PLC or the library...?
Any hint is much appreciated!
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
public static void testSimple() throws Exception {
Register[] r;
int v=0, i=0;
ModbusTCPMaster modbus = new ModbusTCPMaster("10.0.0.221");
modbus.connect();
while (i<100000) {
try {
r=modbus.readMultipleRegisters(i, 1);
v=r[0].getValue();
if (v!=0) System.out.println(i+" = "+v);
i++;
} catch(Exception e) { System.out.println("ERROR at pos "+i+": "+e.getMessage()+". Retry!"); modbus.disconnect(); modbus.connect(); }
} // while
}; // testSimple
this way the code runs thru - even over a high latency vpn.
hence I can work around the problem. But I still fail to understand how it's possible to ever get 'null' back - I'd expect a valid object or an exception...?
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
It's hard to tell from the code what may be happening, but I'll answer the question about exceptions -- you may not receive an exception on a timeout or when you receive a malformed packet. The main loop in the execute() method will retry however many times the retries are set for. If they all fail, without some lower level exception occuring, you get back a null and that's normal.
What can you tell me about the version you're running and anything else. There was a recent change to stop sending a byte of urgent data to verify a connection was still valid. Some Modbus/TCP slaves seem to respond poorly to that.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
latest code (source) from sourceforge (February 14th).
Beeing in the same network segment I don't get any problem. 2 routers later once in 50'000 requests and over a vpn and high latency about once every 10'000 requests.
Doing a disconnect/reconnect and repeat the request seems to recover in 100% of the cases.
Since the problem happens seldom, I'm able to recognize/catch it and you name it '...and that's normal' I'll think that I'll simply work around it.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I thought one more time about "without some lower level exception occuring, you get back a null and that's normal".
I feel an 'execute'-like function should either return a return-code (e.g. C-style int) or throw an exception (java-style): trying to read a value and not getting a valid object is clearly an error-condition which requires particular treatment.
The way I understand the code now it either throws an exception or returns 'null' if a problem occurs - and we have to check for both conditions to make sure the result is valid.
I propose the following change to ModbusTCPTransaction.execute:
check for null response and treat it as any other exception: repeat the request retryLimit times and if it is still 'null' throw the same ModbusIOException
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Dear all
I'm trying to interact with an ABB 595 over modbus/tcp.
It basically works fine, but under some load I sometimes get a 'null' object back. This happens after a couple of hunderd to thousand loops.
in these cases the connection remains connected and the null object comes after the request almost imediately back (definately not a after the timeout). The network is stable, ping-response-time is short and does not change much (no relationship to the 'null' objects)
In my understanding I should get either a valid object - or an exception back...?
I'm calling that from several small methods to get the desired datatype:
single calls work perfectly. I found the problem by 'torturing' it:
the null-object may be returned in the first iterations or after some thousand calls....
Is this a lack of my understanding, the PLC or the library...?
Any hint is much appreciated!
Retried with a different (simplistic) approach:
this way the code runs thru - even over a high latency vpn.
hence I can work around the problem. But I still fail to understand how it's possible to ever get 'null' back - I'd expect a valid object or an exception...?
It's hard to tell from the code what may be happening, but I'll answer the question about exceptions -- you may not receive an exception on a timeout or when you receive a malformed packet. The main loop in the execute() method will retry however many times the retries are set for. If they all fail, without some lower level exception occuring, you get back a null and that's normal.
What can you tell me about the version you're running and anything else. There was a recent change to stop sending a byte of urgent data to verify a connection was still valid. Some Modbus/TCP slaves seem to respond poorly to that.
latest code (source) from sourceforge (February 14th).
Beeing in the same network segment I don't get any problem. 2 routers later once in 50'000 requests and over a vpn and high latency about once every 10'000 requests.
Doing a disconnect/reconnect and repeat the request seems to recover in 100% of the cases.
Since the problem happens seldom, I'm able to recognize/catch it and you name it '...and that's normal' I'll think that I'll simply work around it.
I thought one more time about "without some lower level exception occuring, you get back a null and that's normal".
I feel an 'execute'-like function should either return a return-code (e.g. C-style int) or throw an exception (java-style): trying to read a value and not getting a valid object is clearly an error-condition which requires particular treatment.
The way I understand the code now it either throws an exception or returns 'null' if a problem occurs - and we have to check for both conditions to make sure the result is valid.
I propose the following change to ModbusTCPTransaction.execute:
check for null response and treat it as any other exception: repeat the request retryLimit times and if it is still 'null' throw the same ModbusIOException