Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Application stuck on poor network - Socket error 10054 #68

Open
AkLim94 opened this issue Nov 6, 2024 · 7 comments
Open

Application stuck on poor network - Socket error 10054 #68

AkLim94 opened this issue Nov 6, 2024 · 7 comments

Comments

@AkLim94
Copy link

AkLim94 commented Nov 6, 2024

Hi

I experience some issues with the Modbus component. I noticed when the socket error 10054 append (The connection is reset by the peer application) during ReadInputRegisters, ReadCoil, etc... the component raise an exception and stuck.
Application can not be controlled anymore...

Regards

@JensMertelmeyer
Copy link
Contributor

If the server unexpectedly closes the connection (without notifying the peer!), it will depend on the Timeout property of the TIdModBusClient for how long the ReadInputRegisters(..) will block.

By default, it is 15_000 ms. You might want to lower that volume and make sure your I/O is done in a background thread, not the main thread.

@AkLim94
Copy link
Author

AkLim94 commented Nov 20, 2024 via email

@JensMertelmeyer
Copy link
Contributor

JensMertelmeyer commented Nov 22, 2024

I honestly cannot reproduce your problem. If the server unexpectedly closes (or resets) the connection, then the TIdModbusClient will hang until the timeout is elapsed. This certainly cann be improved (I think).

But I cannot reproduce that something completely hangs up and never returns.

I have used these components with hundreds of installations around the globe in heavy industrial lines, with external servers and clients from different manufacturers, as well as our own microchips.

Consider the following Windows console application:

uses
	IdModbusServer,
	IdModBusClient,
	IdContext,
	ModbusTypes;

type
	TTest = class
		class procedure HandleReadInputRegisters(
			const Sender: TIdContext;
			const RegNr, Count: Integer;
			var Data: TModRegisterData;
			const RequestBuffer: TModBusRequestBuffer;
			var ErrorCode: Byte
		);
		class procedure TestConnectionResetByPeer();
	end;

class procedure TTest.HandleReadInputRegisters(
	const Sender: TIdContext;
	const RegNr, Count: Integer;
	var Data: TModRegisterData;
	const RequestBuffer: TModBusRequestBuffer;
	var ErrorCode: Byte
);
const
	ERROR_ILLEGAL_ADDRESS = $02;
begin
	// Just reset the connection
	// Sender.Connection.Socket.Binding.Reset();

	// just close the connection
	//Sender.Connection.Disconnect();

	// send back a peaceful error code
	ErrorCode := ERROR_ILLEGAL_ADDRESS;
end;

procedure tryReadFrom(const client: TIdModBusClient);
const
	REGISTER_NUMBER = 123;
var
	registerValue: UInt16;
begin
	try
		if(client.ReadInputRegister(REGISTER_NUMBER, {out} registerValue)) then
			WriteLn('registerValue: ', registerValue)
		else
			WriteLn('Nothing read back');
	except
		WriteLn('Reading the register failed');
	end;
end;

class procedure TTest.TestConnectionResetByPeer();
var
	server: TIdModBusServer;
	client: TIdModBusClient;
begin
	// set up a test server
	server := TIdModbusServer.Create(nil);
	server.OnReadInputRegisters := HandleReadInputRegisters;
	server.Active := True;

	// set up our client
	client := TIdModbusClient.Create(nil);
	client.Host := '127.0.0.1';
	client.TimeOut := 1000 {ms}; // Feel free to play with this timeout value

	tryReadFrom(client);
	tryReadFrom(client);

	WriteLn('We''re finished');
end;

begin
	TTest.TestConnectionResetByPeer();
end.

Adjust the HandleReadInputRegisters(..) as you see fit - You will see that the modbus client will always recover and the duration of how long it waits can be controlled with the Timeout property.

@JensMertelmeyer
Copy link
Contributor

Also, have you considered using a network analyzing tool like Wireshark to see what exactly goes over the wire?

@AkLim94
Copy link
Author

AkLim94 commented Nov 22, 2024 via email

@AkLim94
Copy link
Author

AkLim94 commented Nov 22, 2024 via email

@AkLim94
Copy link
Author

AkLim94 commented Nov 25, 2024

Hi,

I built a modbus test server to simulate the socket reset by peer error.
Strange thing no exception generated (I don't understand yet why sometimes I got an exception) by the component when I reset the connection on the server side and the result is:

  • readXXXX, writeYYYY functions return false after a timeout <== I'm OK with this behavior
  • IdModBusClient.Connected property is still at True <== Why is it still marked as connected because in reality the connection is broken?

What I've done in my app to test, after an amount of false returned by readXXX/writeYYYY (after an socket error 10054, as connected flag is still in true value), I release (free up) the component, recreate it and perform a new connection to the modbus controller .

But I noticed a strange and annoying behavior, I can destroy/recreate the component for 3 - 4 times with success (without any exception), perfom readXXX, writeYYYY with success until the next 10054 error where I free and recreate again and then the component lock the background thread on readXXX or writeYYYY functions.
Once this behavior appends nothing can be done, except kill the application...

Is it possible to made a change when 10054 error appends to close / release properly the TCP port used by the component and update the connected flag to false?

Best regards

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants