Apollo3zehn / FluentModbus

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

ModbusTcpClient IsConnected property has defect #39

Closed Zonciu closed 3 years ago

Zonciu commented 3 years ago

Issue

See here

public void Connect(IPEndPoint remoteEndpoint, ModbusEndianness endianness) 
{
...
            _tcpClient?.Close();
            _tcpClient = new TcpClient();

            if (!_tcpClient.ConnectAsync(remoteEndpoint.Address, remoteEndpoint.Port).Wait(this.ConnectTimeout))
                throw new Exception(ErrorMessage.ModbusClient_TcpConnectTimeout);

            _networkStream = _tcpClient.GetStream();
...
}

When _tcpClient.ConnectAsync success, at this moment I close the Modbus Server, _tcpClient.GetStream will be null or disposed, causing ObjectDisposedException or NullReferenceException while reading/writing data.

At this time ModbusTcpClient._tcpClient is not null, ModbusTcpClient.IsConnected is true, but ModbusTcpClient._networkStream is null or disposed. Use if(!ModbusTcpClient.IsConnected) { ModbusTcpClient.Connect(...) } to reconnect will not work.

For now I catch ObjectDisposedException and NullReferenceException, then I create a new ModbusTcpClient to avoid this issue, rather than catch and call Connect directly.

_networkStream is null:

System.ObjectDisposedException: Cannot access a disposed object.
Object name: 'System.Net.Sockets.NetworkStream'.
   at System.Net.Sockets.NetworkStream.Write(Byte[] buffer, Int32 offset, Int32 size)
   at FluentModbus.ModbusTcpClient.TransceiveFrame(Byte unitIdentifier, ModbusFunctionCode functionCode, Action`1 extendFrame) in C:\projects\fluentmodbus\src\FluentModbus\Client\ModbusTcpClient.cs:line 197
   at FluentModbus.ModbusClient.ReadDiscreteInputs(Byte unitIdentifier, UInt16 startingAddress, UInt16 quantity) in C:\projects\fluentmodbus\src\FluentModbus\Client\ModbusClient.cs:line 237
...

_networkStream is disposed:

image

Apollo3zehn commented 3 years ago

Thank you, I´ll check the later today. I was just about to publish an update so I can include a fix for this.

Apollo3zehn commented 3 years ago

I think there is no way to solve this. ModbusTcpClient.IsConnected checks for TcpClient.Connected which again checks for Socket.Connected, which states the following:

https://github.com/dotnet/runtime/blob/e22cf553e11d500c1523034f2c7ff745014e0629/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs#L334-L338

So I am afraid I cannot do something about it, except you have an alternative solution.

Zonciu commented 3 years ago

I see, I will use try-catch to create a new ModbusTcpClient to avoid this issue.