Apollo3zehn / FluentModbus

Lightweight and fast client and server implementation of the Modbus protocol (TCP/RTU).
MIT License
189 stars 71 forks source link

Add timeout for ModbusRTUClients #47

Closed LukasKarel closed 2 years ago

LukasKarel commented 3 years ago

If you use ReadRegisters Function and no server is connected or does not respond, you are stuck in the while loop in TransceiveFrame. There should be a possibility to set a timeout to return with error.

Apollo3zehn commented 3 years ago

What happens, when the server does not respond? Is the read method blocking indefinitely oder does it return with zero bytes read?

There is a read timeout property available in the Modbus RTU client class. Does it not work?

Which framework version are you using?

KristofVerbiest commented 3 years ago

I can confirm this issue. I am using .net core 3.1. The read method is blocked indefinitely.

The readtimeout is only used to pass it to the SerialPort. This timeout never triggers. As LukasKarel mentioned, probably the code is stuck in the while loop.

[edit] I've added some logging, and it is the call await _serialPort.ReadAsync(...) that is blocked indefinitely, even though the ReadTimeOut and WriteTimeOut have been set to 1000ms. I am running this on Linux (armv7l).

KristofVerbiest commented 3 years ago

For me, the workaround for this problem is to use the non-async versions of the methods. The async versions are stuck in this method on ModbusRtuSerialPort:

public Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken token)
{
    return _serialPort.BaseStream.ReadAsync(buffer, offset, count, token);
}

It seems that the timeout is not taken into account when accessing the BaseStream of the serial port.

Apollo3zehn commented 3 years ago

The problem is that the implementation from Microsoft is not done properly and now we need to workaround that somehow (https://github.com/dotnet/runtime/issues/28968).

I have tried several solutions but it looks like the one from AndreasAmMueller is working the best: https://github.com/AndreasAmMueller/Modbus/blob/a6d11080c2f5a1205681c881f3ba163d2ac84a1f/src/Modbus.Serial/Util/Extensions.cs#L70-L102

Can you please check if my latest commit to the dev branch solves your issues (https://github.com/Apollo3zehn/FluentModbus/commit/88a4a3bc56f133194b26ebeaa1fe2cc45fb91126)?

I am wondering why AndreasAmMueller checks if the workaround code is running under Windows. This implies that it should run under Linux but apparently it doesn't in your case. Therefore I have not implemented such a check and use that code on every OS.

KristofVerbiest commented 3 years ago

With your latest commit on the dev branch, this now works as expected.

Thanks for your support!