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

TCP slave is stuck #40

Open
daremi opened this issue Mar 31, 2019 · 8 comments
Open

TCP slave is stuck #40

daremi opened this issue Mar 31, 2019 · 8 comments

Comments

@daremi
Copy link

daremi commented Mar 31, 2019

I'm building Tomcat application to simulate Slave device. First query works, all data is read by external software (https://www.modbustools.com/), but then external software is stuck. Here are the logs on Slave:

Client connected /127.0.0.1
INFO: Frame recv: 00000000000601030000000A
onReadHoldingRegisterRange: address 0, quantity 10
INFO: Frame sent: 0000000000170103140000006F00DE001501BC00000000000000000026
WARNING: java.net.SocketTimeoutException: Read timed out
Client disconnected /127.0.0.1

If I run parallel instance of external software it is not getting data, logs on Slave:

Client connected /127.0.0.1
WARNING: java.net.SocketTimeoutException: Read timed out
Client disconnected /127.0.0.1

Sometime at that even first external software got one response, but then stuck again.

When trying Disconnect in external software, it freeze and stop responding, so it might be something with network handling.

Code on Slave:

        try {

            ModbusSlaveTCP slave;

            TcpParameters tcpParameters = new TcpParameters();

            tcpParameters.setHost(InetAddress.getLocalHost());
            tcpParameters.setKeepAlive(true);
            tcpParameters.setPort(33000);

            slave = (ModbusSlaveTCP) ModbusSlaveFactory.createModbusSlaveTCP(tcpParameters);
            
            Modbus.setLogLevel(Modbus.LogLevel.LEVEL_VERBOSE);

            MyOwnDataHolder dh = new MyOwnDataHolder();          
            dh.addEventListener(new ModbusEventListener() {
                
                @Override
                public void onReadHoldingRegisterRange(int address, int quantity) {
                    System.out.println("onReadHoldingRegisterRange: address " + address + ", quantity " + quantity);
                }

            });
            
            Observer o = new ModbusSlaveTcpObserver() {
                @Override
                public void clientAccepted(TcpClientInfo info) {
                    System.out.println("Client connected " + info.getTcpParameters().getHost());
                }

                @Override
                public void clientDisconnected(TcpClientInfo info) {
                    System.out.println("Client disconnected " + info.getTcpParameters().getHost());
                }
            };
            slave.addObserver(o);
            
            slave.setDataHolder(dh);
            hr = new ModbusHoldingRegisters(10);
            hr.set(0, 12345);
            hr.set(1, 111);
            slave.getDataHolder().setHoldingRegisters(hr);
            slave.setServerAddress(1);
            
            slave.listen();

        } 
        catch (RuntimeException e) {
            throw e;
        } 
        catch (Exception e) {
            e.printStackTrace();
        }

Terminating external software and run again is not helping.

Best regards,

@browncrane
Copy link
Contributor

onReadHoldingRegisterRange: address 0, quantity 10
It seems like 10 registers are required. However,

            hr = new ModbusHoldingRegisters(10);
            hr.set(0, 12345);
            hr.set(1, 111);

you only set two. It's a usage problem.

@daremi
Copy link
Author

daremi commented Apr 1, 2019

I have removed the rest eight registers from the code above to make it shorter.

@browncrane
Copy link
Contributor

see the example

below line 94

            if (slave.isListening()) {
                Runtime.getRuntime().addShutdownHook(new Thread() {
                    @Override
                    public void run() {
                        synchronized (slave) {
                            slave.notifyAll();
                        }
                    }
                });

                synchronized (slave) {
                    slave.wait();
                }

                /*
                 * using master-branch it should be #slave.close();
                 */
                slave.shutdown();
            }

In your code, the slave would be destroy after the first request.

@daremi
Copy link
Author

daremi commented Apr 1, 2019

Thanks for ideas. Added code:

            System.out.println("before slave.isListening()");
            if (slave.isListening()) {
                Runtime.getRuntime().addShutdownHook(new Thread() {
                    @Override
                    public void run() {
                        synchronized (slave) {
                            slave.notifyAll();
                        }
                    }
                });

                synchronized (slave) {
                    slave.wait();
                }

                /*
                 * using master-branch it should be #slave.close();
                 */
                slave.shutdown();
            }
            System.out.println("after slave.isListening()");

and here are the logs (two requests from external software):

before slave.isListening()
Client connected /10.171.99.99
INFO: Frame recv: 00000000000601030000000A
onReadHoldingRegisterRange: address 0, quantity 10
INFO: Frame sent: 0000000000170103143039006F00DE014D01BC022B029A0309037803E7
WARNING: java.net.SocketTimeoutException: Read timed out
Client disconnected /10.171.99.99
Client connected /10.171.99.99
WARNING: java.net.SocketTimeoutException: Read timed out
Client disconnected /10.171.99.99

After that external software is freezing. In log there is no "after slave...", so this thread is waiting on wait() on tomcat side. I could run it as separate thread, but if synchronous not working, async will not either...
What is interesting, on debuging line by line, (without if() block) external software works fine until Resume thread.

@ippodamia
Copy link

I tested the slave shutdown code from the SimpleSlaveTCP.java example (line 99-117). My Slave is connected with a Master. I noticed that the code blocks in the wait method and never continuous with the shutdown of the slave. The communication with the Master is not aborted.

I then used the code from the ModbusTest.java and the ExampleTCP.java i.e.:

 try {
       slave.shutdown();
  } 
  catch (ModbusIOException e) {
        e.printStackTrace();
 }

This does not block but it still does not interrupt the communication with the Master.

Only when I also set a new empty DataHolder to the slave, is the communication with the Master really interrupted:

 try {
       this.slave.setDataHolder(new DataHolder());
       slave.shutdown();
  } 
  catch (ModbusIOException e) {
        e.printStackTrace();
  }

Should perhaps the reset of the DataHolder be part of the slave shutdown method?

Best Regards

@browncrane
Copy link
Contributor

Hi @ippodamia, What do you mean by?

it still does not interrupt the communication with the Master.

What type of Slave you are using?

@ippodamia
Copy link

ippodamia commented Apr 17, 2019

Hello browncrane.
I am using a ModbusSlaveTCP slave. After the slave.shutdown(); method has been called the slave is not null and slave.isListening() returns false. I can see that my Master is still connected to the Slave (makes read requests that are getting answered).
I would expect that after the ModbusSlaveTCP.shutdownImpl() has been executed the ServerSocket should be closed and my Master should loose its connection.

Since the Socket has not been closed, the DataHolder of the Slave does not know that the Slave has been shutdown. I could check in my DataHolder methods (f.e. readHoldingRegisterRange()) if the slave is still listening, in order to detect that the Slave has been shutdown.

@KWSimon
Copy link

KWSimon commented Jan 30, 2020

Hi @browncrane and @ippodamia,

I ran into the same issue as @ippodamia. After calling the slave.shutdown() method, Modbus TCP requests received by my application keep being processed.

From my understanding of the code I looked into, the issue come from the following :

The method RequestHandlerTCP.closeConnection() is not called by the class ModbusSlaveTCP (as it is by ModbusSlaveSerial).
As a consequence setListening(false) is not called neither and the method RequestHandler.isListening() keep return true.
So the condition to end the "infinite" loop processing the requests in RequestHandlerTCP.run() is never matched and the connection never closed.

I haven't found any workaround since no reference on the RequestHandlerTCP is keeped in ModbusSalveTCP that would allow to call the closeConnection() method.

com.intelligt.modbus.jlibmodbus.slave.ModbusSlaveTCP.run()

 @Override
    public void run() {
      [...]
                    threadPool.execute(new RequestHandlerTCP(this, s));
      [...]
    }

I hope this will help.

Simon

ps : I'm using the version 1.2.9.7

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

4 participants