print "$unitId: Command response: $_" while <$client>;
Which should only happen (under normal circumstances) when the gprs client closes the connection.
Oshalla has pointed out that if the physical transport layer is disconnected, or if the client simply hangs, then that read will never return as coded. And that is the original problem you are trying to solve.
I think that the solution (hinted at above) is to use setsockopt with SO_RCVTIMEO, to effect an inactivity timer on reads. From a *nix manpage for setsckopt:
SO_RCVTIMEO is an option to set a timeout value for input operations. It
accepts a struct timeval parameter with the number of seconds and
microseconds used to limit waits for input operations to complete. In
the current implementation, this timer is restarted each time additional
data are received by the protocol, and thus the limit is in effect an
inactivity timer. If a receive operation has been blocked for this much
time without receiving additional data, it returns with a short count or
with the error EWOULDBLOCK if no data were received. The struct timeval
parameter must represent a positive time interval; otherwise,
setsockopt() returns with the error EDOM.
This works perfectly on my system(*). With your clients sending regular data, the timeout gets reset to the value you supply each time something is received.
If you were to set a value of (say) 3x the frequency of that regular update, then if the client hangs, or the transport is cut for any reason, it will timeout the read whenever 3 updates have been missed. That would make for very simple client thread procs and a very reliable server.
My suggestion to you is to try this in your existing working code:
...
if( $lclient->connected ){
## I'm assuming that the setsockopt implementation on your sys
+tem
## will build the appropriate struct timeval from 15.0
setsockopt( $client, SOL_SOCKET, SO_RCVTIMEO, 15.0 ) or $!;
while( <$lclient> ) {
...
You might need to switch from readline (<$client>) to recv... which means you'd need to do your own buffering.
You should also note that your current code (despite is "working" status) contains a lot of very dubious code. Particularly with respect to no locking and sharing through cloning. That's why I tried to provide you with a simplified "equivalent", before trying to address the OP problem. Unfortunately, the differences between or two systems make trying to work out why my code doesn't work on your system rather difficult. I knew there would likely be some problems, but if you can't get it to work at all, there is no base to work from. (It runs very nicely here!).
When done from C! I haven't worked out the combination of magic required to do it from Perl yet :(
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
|