Hoobs

EIP issue with closing/opening sockets

15 posts in this topic

NJ501-1300.

Attached is a simple program that just opens a socket, reads one message off of it and echos that message back to the socket, then closes the socket.  I have a socket client that I'm using to send small strings to the socket, and I can choose whether or not the client closes the socket from it's end.  The first time I execute this it after a reset it works great.  However, after that, I can never connect to this socket again.  The only way to recover is to pull the ethernet cable and plug it back in or, sometimes, I have to actually power cycle the NJ.  Then, I can connect from my client, send/receive the message into the socket again successfully, and then again find myself back in the state where I can't can't connect.  This is consistent regardless of whether the client is closing the socket from its end or not.

I've tried to strip this down to the shortest example I can.  Anybody have an idea what's happening?  It seems to me that as soon as the socket is closed the next time around the SktTCPAccept instruction should hang on the closed socket, awaiting a request to come in from the network.  But it appears there is something happening deeper down in the networking stack that prevents this, and the only way to fix it is to pull the cable or power cycle the NJ, neither of which is acceptable for production, obviously.  If I can get this working then I intend to also explore persistent connections for throughput reasons, but I need to get this  more simple example fully working first.

Thanks!
--Al

Sysmac ladder.pdf

Share this post


Link to post
Share on other sites

OK, I have learned a bit more...  the problem appears to specifically affect the SktTCPAccept instruction.  After a full reset, the attached program works as expected, the SktTCPAccept opens a socket, listens on it for incoming data, etc.  However, once that has all occurred, if I restart the NJ (without resetting it, or the EIP subsystem), then the attached program stops at the SktTCPAccept instruction and does not continue.  No prior instruction has thrown an error, and neither is the SktTCPAccept.  I have looked at every parameter, and nothing is out of the ordinary.  But something is happening under the hood that is causing this instruction to stop in its tracks. 

The attached screenshot show the power trace when SktTCPAccept gets into this situation.  The parameter values can be seen.  Why is the instruction stopping?

Thanks!
--Al

 

SktTCPAccept problem.PNG

Share this post


Link to post
Share on other sites

One more follow-up:  I have found that, after the first transaction that works, if I unplug the ethernet cable from the NJ, wait a few seconds, and plug it back in then I can do one successful transaction again before it locks up.  Whatever condition is preventing the SktTCPAccept instruction from running is not visible in Sysmac Studio, but it can be cleared by disconnecting the physical layer and connecting it back up.  I need to know what that condition is.

Any thoughts?  Hep me, hep me, please!  :)

--Al

Share this post


Link to post
Share on other sites

I'm not sure... seeing no ErrorID or Error flag popping out, it means your instruction was run OK.
Also the Done flag should only lit-up if the connection is established with a client.

Do you close the socket in NJ after read/write activity using the SktClose or not? Because if plugging out ethernet cable made the re-enables the SktTCPAccept, that's because the port was closed automatically by the hardware design.

But if you tried to open using SktTCPAccept twice on a same socket handler (your socketNum) without properly closing the port first, it'll get stuck. I might be wrong about it, but I believe when a client closed a socket connection, it closes it's own local port and not the servers port. That means the server also need to properly close it's port first before attempting to receive another session, isn't it?

Share this post


Link to post
Share on other sites

Hi Innoaloe, thanks for taking a look at this.  Please look at the pdf I uploaded with the original post on this topic.  This ladder diagram executes exactly as described above, and I can see the power trace run through the SktClose instruction and terminate with no error.  However, after the SktClose is executed, the SktTCPAccept still behaves as if the socket is open and active.  I understand that the reason I can't connect the second time is because SktTCPAccept is confused about the socket being closed (after I've already closed it), but the questions are:

  1. Why is it confused?
  2. How can I either avoid getting it confused, or how can I get it unconfused without resetting the entire network stack (which is what removing the physical media accomplishes, in a crude manner...)?  There will be other network/socket transactions going on simultaneously, so resetting the entire network stack between connections is not viable.

I'm stuck at the moment, having tried many different sequences of events in an attempt to find something that doesn't leave SktTCPAccept in this state of affairs.  Any thoughts, suggestions or other observations welcomed!

Best,
Al

Share this post


Link to post
Share on other sites

OK, I have found a workaround for this problem, I describe it below.  Unless I'm confused (always possible, LOL!) this is possibly a bug, maybe in SktTCPAccept, maybe further down the stack, there's no way to tell from this vantage point.

When using ladder logic, my expectation is that each time execution of a rung is started every function and function block on that rung have their constructors/initializers called (under the hood).  I made a guess that possibly SktTCPAccept wasn't leaving itself in a clean state after its first invocation, and was then confused at subsequent invocations.  So, at the end of the rung with the Accept, after I had set a flag variable to release other rungs, I have an Inline ST block with one line in it:

SktTCPAccept_instance(Execute:=FALSE);

This causes SktTCPAccept to be explicitly initialized before each subsequent invocation.

If I was doing persistent socket connections, this wouldn't work.  However, it appears that the NJ is also closing sockets after each network transaction, even if I'm not doing an explicit close.  That's OK, I can deal with opening/closing a connection for each transaction in this situation.  However, if the NJ is closing sockets "automatically", behind the back of the program, that should be considered a bug as well.

Hope this helps the next newbie...    enjoy!

Best,
--Al

Edited by Hoobs

Share this post


Link to post
Share on other sites

Hello,

I dont really know much about this topic, but never to late to learn, so I looked around in the NJ/NX series CPU unit built-in EtherNet/IP Port user’s manual (W506). On page 344 under precautions for TCP socket services I found this:

On the third point it says you cannot reopen a closed socket with the same port untill 60 sec has gone by. I dont know if the value of your portNum variable is changing between connections, but if it remains the same this might be the problem.

Share this post


Link to post
Share on other sites
16 hours ago, Hoobs said:

When using ladder logic, my expectation is that each time execution of a rung is started every function and function block on that rung have their constructors/initializers called (under the hood).  I made a guess that possibly SktTCPAccept wasn't leaving itself in a clean state after its first invocation, and was then confused at subsequent invocations.  So, at the end of the rung with the Accept, after I had set a flag variable to release other rungs, I have an Inline ST block with one line in it:


SktTCPAccept_instance(Execute:=FALSE);

This causes SktTCPAccept to be explicitly initialized before each subsequent invocation.

If I was doing persistent socket connections, this wouldn't work.  However, it appears that the NJ is also closing sockets after each network transaction, even if I'm not doing an explicit close.  That's OK, I can deal with opening/closing a connection for each transaction in this situation.  However, if the NJ is closing sockets "automatically", behind the back of the program, that should be considered a bug as well.

Hello Hoobs, it was a good thing you managed to find a solution. I looked into your PDF and this is the comment that I can give :

  1. I don't see any thing that can change the value of statusTCP, so statusTCP and statusTCPClosed value might always be the same, which means the "Execute" input of SktTCPAccept is always On. I might be wrong about statusTCP value is never changing though, maybe you put it elsewhere
     
  2. Typically if you want to re-execute Omron Function Blocks, the Execute Input will need to be turned Off before going On again. This is true for SktTCPAccept. If what I said in point 1 is correct, since your statusTCP and statusTCPClosed value is always equal, you will never reset the value of the SktTCPAccept Execute input, thus it never got retriggerred.
     
  3. If point 1 and 2 are correct, this also explains why after cable disconnection you can execute the SktTCPAccept again properly, since the _EIP_EtnOnlineSta flag will go Off then On again, resetting the Execute input of the FB.
     
  4. The Inline ST Program you add there did just that. Forcing the Execute Input to False, thus the SktTCPAccept can be retriggered.

 

16 hours ago, Solheim95 said:

Hello,

I dont really know much about this topic, but never to late to learn, so I looked around in the NJ/NX series CPU unit built-in EtherNet/IP Port user’s manual (W506). On page 344 under precautions for TCP socket services I found this:

On the third point it says you cannot reopen a closed socket with the same port untill 60 sec has gone by. I dont know if the value of your portNum variable is changing between connections, but if it remains the same this might be the problem.

This is a good catch, however it is true only if we're using NJ as a TCPClient, which is using SktTCPConnect Function Block. In OP case he is using NJ as TCPServer, so that rule doesn't count.

Share this post


Link to post
Share on other sites

Thanks, Solheim95...  I had not noticed that.  It's not the problem I was having but it could cause me a problem, I'm glad you pointed it out!

Now, the question is:  Why is this the case?  I can see no scenario where this behavior would be desired...

--Al

Share this post


Link to post
Share on other sites
Just now, innoaloe said:

2. Typically if you want to re-execute Omron Function Blocks, the Execute Input will need to be turned Off before going On again. This is true for SktTCPAccept. If what I said in point 1 is correct, since your statusTCP and statusTCPClosed value is always equal, you will never reset the value of the SktTCPAccept Execute input, thus it never got retriggerred.
count.

Innoaloe, thanks very much for digging back into this with me, I appreciate it.  Two thoughts:

  • Even though it doesn't affect me, the 60-second hold-off with SktTCPConnect still doesn't make sense to me.  Why would the controller enforce such a hold-off?
  • Your point I quoted above: This is unusual to me, I'm really lucky I had a chance to learn this early in my NJ experience.  I expected these blocks to be reentrant, but that is obviously not the case if the Execute in-parm has to be forced to cycle through False to reset a block before it can be executed again.  I can work with it, this is just different from some other situations I've been in where blocks could be re-executed on subsequent passes without this requirement being in place.

Thanks!--Al

Share this post


Link to post
Share on other sites
Just now, Hoobs said:

Even though it doesn't affect me, the 60-second hold-off with SktTCPConnect still doesn't make sense to me.  Why would the controller enforce such a hold-off?

I also didn't understand this one... I've mentioned in another thread to you also, for older model CP1L-E series, it will hold-off 120 seconds instead of 60 seconds :D.
This should be some hardware/firmware design issue that cannot enforce closing off a Port.

Just for reference should you need TCPClient with SktTCPConnect in the future, you can avoid this by setting the LocalPort of the PLC to 0. This way, every time you attempt to create a connection, the PLC will automatically find any port number available to use (It will search from 4096, then 4097 onwards IIRC). The only downside is that for any successive session, the PLC port number is always different, which may be an issue with the Server firewall settings.
 

Just now, Hoobs said:

Your point I quoted above: This is unusual to me, I'm really lucky I had a chance to learn this early in my NJ experience.  I expected these blocks to be reentrant, but that is obviously not the case if the Execute in-parm has to be forced to cycle through False to reset a block before it can be executed again.  I can work with it, this is just different from some other situations I've been in where blocks could be re-executed on subsequent passes without this requirement being in place.

This is a design choice that Omron made. Most Execute In-Param only detects Off to On transition (Rising-Edge). This is done to avoid multiple-triggering of an FB with intermittent action that is currently in process (Busy Out-Param On, Done Out-Param still Off) on the next program scan cycle.
This is not the case however for FBs with continuous Action such as Jogging a servo motor.

You might already know this, but every Function Block provided from Omron is equipped with a help file (press F1 when selecting the FB) that also provides timing diagram. You can refer to those to check how to trigger it in a program.

Share this post


Link to post
Share on other sites
Just now, innoaloe said:

You might already know this, but every Function Block provided from Omron is equipped with a help file (press F1 when selecting the FB) that also provides timing diagram. You can refer to those to check how to trigger it in a program.

No, I had not discovered that here in my early days with Sysmac Studio, that will be extremely helpful -- thanks!!!

Regards,
--Al

Share this post


Link to post
Share on other sites
On 10/23/2017 at 1:42 PM, innoaloe said:

Hello Hoobs, it was a good thing you managed to find a solution. I looked into your PDF and this is the comment that I can give :

  1. I don't see any thing that can change the value of statusTCP, so statusTCP and statusTCPClosed value might always be the same, which means the "Execute" input of SktTCPAccept is always On. I might be wrong about statusTCP value is never changing though, maybe you put it elsewhere
     
  2. Typically if you want to re-execute Omron Function Blocks, the Execute Input will need to be turned Off before going On again. This is true for SktTCPAccept. If what I said in point 1 is correct, since your statusTCP and statusTCPClosed value is always equal, you will never reset the value of the SktTCPAccept Execute input, thus it never got retriggerred.
     
  3. If point 1 and 2 are correct, this also explains why after cable disconnection you can execute the SktTCPAccept again properly, since the _EIP_EtnOnlineSta flag will go Off then On again, resetting the Execute input of the FB.
     
  4. The Inline ST Program you add there did just that. Forcing the Execute Input to False, thus the SktTCPAccept can be retriggered.

 

This is a good catch, however it is true only if we're using NJ as a TCPClient, which is using SktTCPConnect Function Block. In OP case he is using NJ as TCPServer, so that rule doesn't count.

Hi Innoaloe,

 

To your last point about the TCPClient and TCP Server. I am just now getting into the world of socket communications of industrial automation and I would like to clear something up. If you are trying to communicate to a server using socket TCP to send data to that server, would you use an Accept, or a Connect function block?

Share this post


Link to post
Share on other sites

If you are initiating the message to the server, that's CONNECT.

Share this post


Link to post
Share on other sites
On 5/5/2020 at 1:34 AM, PenneyInstruments said:

Hi Innoaloe,

 

To your last point about the TCPClient and TCP Server. I am just now getting into the world of socket communications of industrial automation and I would like to clear something up. If you are trying to communicate to a server using socket TCP to send data to that server, would you use an Accept, or a Connect function block?

Hello @PenneyInstruments. As what Crossbow mentioned, if the PLC is acting as the TCP Client, then you should use SktTCPConnect FB.
If all your connection parameters are correct, the communication will be established if the device at the Server side is accepting connections.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now