Host Engineering Forum
General Category => Do-more CPUs and Do-more Designer Software => Topic started by: plcnut on May 23, 2013, 03:08:56 PM
-
I am using TCPOPEN and then streaming out data to a networked printer (Zebra GX42). It works super except that if I wait over a certain amount of time (~5-10 minutes), the printer will not respond. I can resend and then it works perfect.
I assemble all the data strings in one program block and then I have all the TCP code in another program block that I call. I call TCPOPEN every time I enter the program, but I only call CLOSE when there is an error(which hasn't happened yet), should I close the connection each time I print? Or maybe have a timer that will call the CLOSE if the connection has been idle for a certain amount of time?
I still don't understand the CLOSE instruction and when it IS and IS NOT necessary.
-
TCPOPEN actually performs a TCP connection operation with the "remote" device. This allocates resources and logic on the Do-more side and on the Printer side. It's like a phone call - a connection is being made and both sides are aware of each other. Hence, it's usually good practice to CLOSE it once you are done with it (i.e. hang up when you are done talking). If you are continuously dumping to it (e.g. a line printer every few seconds), then you could keep the TCP connection open and leave it open forever (or at least until the other side "hangs up" on you).
Don't do something like TCPOPEN on every LINE of the report. Open it just like you are doing, at the beginning of your GenerateReport program code-block. I recommend calling CLOSE on the TCP device when done with the report, whether by reaching the end of the report, or by error, or even if the other side terminates your connection prematurely - TCP allows for that and you should handle that because you have absolutely NO CONTROL over that printer's firmware (and when it decided that it's done talking to YOU). I think you monitor the .Connected member of your TCP Client's STREAM structure to if/when the other side hung up prematurely (normally, your CLOSE makes you hang up, which makes the other side hang up).
-
I bet the failure at the 5-10 minutes mark is because your Do-more is NOT calling CLOSE, the printer hasn't heard from you, the line is open, and like a teenager, it doesn't like being ignored, and so it's hanging up on you, which is not being handled by your project.
-
That is what I thought, but am I misunderstanding Bobo in reply #1 on this thread:
http://forum.hosteng.com/index.php/topic,1089.msg9020.html#msg9020
Because it sounds like opening and closing is a bad idea ???
Thanks
-
He was implying the "don't do it for every line of the report". Keep it open for reasonable time, but realize that the other side can (and will) disconnect if it doesn't hear from you after a certain amount of time.
Look at it this way, the Printer gets a TCP connection from the Do-more IP address 1.2.3.4, then you turn off your PLC, how long should the printer maintain that TCP connection with nobody talking to it (remember, Do-more called the Printer)? Most TCP devices put a timeout of 60 seconds, or in the case of your printer, 4 or 5 minutes.
Maintaining those limited resources "forever" will eventually cause issues on many "embedded" systems, be they printers, PLCs, etc.
This type of "network protocol" is best for this printer
GenerateReport PROGRAM:
ESTABLISH CONNECTION
USE CONNECTION
CLOSE CONNECTION
but separately (in a Stage that never ends)
MONITOR CONNECTION => ABORT REPORT
-
Cool. Thank you vey much for the clarification, it makes a lot more sense. I will adjust my code in the morning.
-
As Mark said, TCPOPEN is basically doing 2 things: 1) opening the device driver and 2) creating a connection to a remote server. To CLOSE the device driver will also close the connection to the remote server if it is still open...but...it is possible for the connection to have already been closed by the server.
So...do a TCPOPEN and leave it open as long as you like, but if the .Connected member is ever false, call TCPOPEN again. When you are done, call CLOSE. The problem of opening and closing over and over is related to network resources usage and bad performance. It is completely appropriate to TCPOPEN, do some work, then CLOSE. But don't expect that a server is going to allow you to keep the connection open indefinitely with no activity...very few servers will allow that.
My major concern with TCP connections is that a user will use one client connection to talk to multiple servers flat out...open server 1, transact, close, open server 2, transact, close...ad infinitum. The network stack will eventually get very annoyed with you. Instead, create clients for each server. Open each and leave open and long as you are *actively* transacting, and reopen as required due to drops or kicks. When you are done, close. If you plan to have some time between transactions, go ahead and close immediately...mostly because the server will likely kick you anyway.
Does that help?
-
My major concern with TCP connections is that a user will use one client connection to talk to multiple servers flat out
Now it makes sense, opening and closing is not the issue, but rather using the same internal "device connection" to connect and disconnect with multiple external devices.
-
Even that really isn't true. I'm concerned about the number of new connections established per unit of time. Every socket that has been opened and closed is kept by the stack for a little while. I'm not sure how long he hangs onto them, but it might be as long as minutes. If you open a connection, do work, close, and repeat as fast as possible, the list of closed sockets gets longer and longer, resulting in significant increases in scan time...significant on the order of 10s of milliseconds...I've seen 40ms before.
Since the most likely scenario for churning sockets is because you are using one connection in a round robin of n servers, I recommend multiple connections. In most cases what I am counseling people on is Modbus/TCP mastering, not custom protocols, but the issues are the same.
The key thing is 'don't thrash'. Keep the number of socket open/close operations to reasonable amount and you will never see the issue. Thrash, and your CPU might grind to a halt, spinning through hundreds of closed sockets prior the being purged. Do-more is fast, but we are still vulnarable to bad programmig practice. I'm just encouraging practices that will produce good results every time.
-
Thank you for the explanation Bobo.
I added the CLOSE to the end of each print job, and have eliminated my missed print problem!
-
The ADC tech team is generally pretty leery of custom protocols in Do-more, and for good reason: many of their customers lack the experience required to use those tools effectively. So we walk a fine line between providing the features required for high-end applications, keeping the product usable for the majority of our customers, and keeping the techs from pulling their hair out. To that end, we have generally downplayed the custom protocol functions, knowing that the customers with the level of expertise required to use them effectively probably don't need a great deal of support. I'd say we have erred on the side of not providing enough documentation, and probably should revisit that in the future.
In the meantime...keep asking questions, we'll keep answering them, and in turn the forum will become a knowledge base for other comm savvy customers. Do-more can do some seriously big-boy stuff in the right hands. We want to make sure the right hands know that and have enough information to get good results doing so.
-
I may be experiencing this same issue (trying to talk to a remote device that's hung up), though I'd read this and wrote my ladder in a way that I thought would prevent it.
Application: I need to make 3 or 4 exchanges with a laser controller at some interval from every few seconds to once a day, lets say (loading and initializing the job I'm about to run, which might not change all day or might change every shot)
Ladder: - If .Open and NOT .Connected, CLOSE (because of having read this thread).
- If NOT .Open (because this is the first transaction or because I just CLOSEd it) then OPENTCP.
- Do transactions
- Don't CLOSE at end, because next session may be in a few seconds.
Symptom: Works OK most of the time. Occasionally, laser refuses to respond, although it's powered on and I can ping it. .Open and .Connected show OK. Once it goes into that mode, it's pretty persistent. I believe, although I'm now going to start watching it more carefully, that the problem doesn't go away till you power cycle the laser.
Can you define in detail how .Open and .Connected are determined?
-
If you were to enable a TCPLISTEN you would find that .open is on all the time, but .connected is only on when a client connects.
For your application, you should call OPEN every time, and CLOSE every time. My application works great running this way, the only time I don't CLOSE is if I STREAMOUT (or STREAMIN) multiple times as part of the same session.
(This is all with the assumption of a custom protocol, NOT Modbus)
-
I now officially regret saying anything about leaving the connection open. Sorry. I am bad.
Unless you are opening and closing dozens of times per minute, then open the connection, do your work, and close. Put the code to do the work in a dedicated program. Use the networking instructions' internal stage transition logic...and write the program in Stage. I bet if you do it that way, it pretty much just works. If you don't do it that way, I bet you end up with all kinda weird when the server randomly drops you...which they tend to do during periods of inactivity.
-
Thanks, plcnut and BobO.
BobO -- That's pretty much what I've done. It's in a separate program and I think my logic is pretty solid except that I'm not CLOSEing at the end of each session. If I do that it'll probably work fine.
Just out of curiosity, shouldn't .Connected go away if the other guy hangs up? And wouldn't closing/reopening if NOT .Connected reestablish the connection? Or might the other device ignore the new open request?
-
Yes, .Connected gets dropped when the connection is closed, however, TCP timeouts can be lengthy...on the order of minutes in some cases. There's no telling what the server is doing once things go south. He could have code there designed to deal with denial of service or he could be contemplating his naval in some kind of a timeout. Generally if things are done in the way he expects...connect, do work, disconnect...everyone will be happier.
I assume you have all of your logic properly monitoring the instruction completion/error results and are not moving from operation to operation until each part completes normally, yes? That's the primary reason I push stage. Do it the way we designed it and it is hard to screw up. Code in straight ladder and keep re-coding till it works. I have seen it happen *many* times with various students of Do-more...
-
Yeah, not stage per se, but the equivalent, looking for the success bit from the previous STREAMOUT.
I like looking at boats too.... :D
-
Oh goodness...spelling Nazis on an engineering centric site? No credit for you...it's no challenge! Put that in your naval...um...navel...er...belly button and ponder it!
-
Oh goodness...spelling Nazis on an engineering centric site? No credit for you...it's no challenge! Put that in your naval...um...navel...er...belly button and ponder it!
;D I guess my worst case frequency wise would be like every 3-5 seconds for a couple minutes, then a break of 30-60 seconds and repeat. So you're saying at that pace it's OK to close after each session?
-
Oh goodness...spelling Nazis on an engineering centric site? No credit for you...it's no challenge! Put that in your naval...um...navel...er...belly button and ponder it!
;D I guess my worst case frequency wise would be like every 3-5 seconds for a couple minutes, then a break of 30-60 seconds and repeat. So you're saying at that pace it's OK to close after each session?
If you are referring to your navel, there is no restriction. ;D If you are talking about your printer, that's plenty ok too. It can get silly when you use a single client device to hit half a dozen servers flat out...think Modbus mastering, round robin, no delay. That's why I warned 'nut. Truthfully I shoulda said nothing... :P
-
Cool, thanks! Yeah, if I want to poll multiple devices, I'll set up a device per, and open and close according to the same guidelines.
-
Cool, thanks! Yeah, if I want to poll multiple devices, I'll set up a device per, and open and close according to the same guidelines.
And a stage program code-block per. ;D
-
Why, of course! :)
-
plcnut,
Will you consider posting your code for this?
Thanks
-
plcnut,
Will you consider posting your code for this?
Thanks
For a Zebra printer specifically?
Or are you wanting to talk to something else?
-
I need to print data that has been collected by a DoMore. I know nothing about what a printer needs. Are all printers different?
-
If you just need to print logged data and there is a PC on the network, you could use DMLogger to log to a data file on the PC, then print from the PC.
-
I need to print data that has been collected by a DoMore. I know nothing about what a printer needs. Are all printers different?
The print message/commands will be different for each printer, but the communications method will all be the same. I will see if I can put a generic program block together for you.
-
If you just need to print logged data and there is a PC on the network, you could use DMLogger to log to a data file on the PC, then print from the PC.
That is what I did. They need it printed in a very specific format. So I had them open it in excel and then had a macro that would format and print. They are telling me that that is too complicated.
The print message/commands will be different for each printer, but the communications method will all be the same. I will see if I can put a generic program block together for you.
Thanks
-
What is the printer?
-
Try this example (http://forum.hosteng.com/index.php/topic,1831.0.html).
Please let me know how it goes.
-
Thanks plcnut. I hope to have time to work on this next week. I do have a question after looking through the program. Bits C0 and C3 have to do with the printer queue being full. How is this determined?
Thanks again, you truly are a nut for PLCs.
-
I frequently use Tasks to assemble data and place it into the queue using STRPRINT. Many times this data is being assembled inside a FOR/NEXT loop using indexed fields (like a database table inside Do-more). When the queue gets full, then I will set a bit to indicate that I have more data coming, then call the code block that sends out the data. As soon as I have finished streaming out the queue, then I will call the Task to continue where it left off and fill the queue again.
Rinse, Lather, Repeat...
-
Here is a screenshot where I am assembling a csv file that is then streamed out to a client.
You will notice that I monitor the length of the queue so that I can exit and stream the queue, but once the data is all assembled it exits with the 'c_AssemblyDone' bit, so that my Stream code block knows what to do.
(https://forum.hosteng.com/proxy.php?request=http%3A%2F%2Fi761.photobucket.com%2Falbums%2Fxx256%2Fplcnut%2FPLCs%2FAssembleLogData_zpsenxxh2ob.png&hash=e1e12ac04a4b03cf1c942dd2060420eb5690b9f4) (http://s761.photobucket.com/user/plcnut/media/PLCs/AssembleLogData_zpsenxxh2ob.png.html)
-
So we walk a fine line between providing the features required for high-end applications, keeping the product usable for the majority of our customers, and keeping the techs from pulling their hair out.
Easy peasy. Just hire completely bald techs, and you can write any features you want.