in reply to Re^6: Non closing sockets - threads
in thread Non closing sockets - threads

does your script end the connection after it receives gprs client data or keeps waiting for next data from client.

This loop in gprsClient() will (does on my system), continue to read and print anything that arrives from the gprs client until the client socket is close or an error occurs:

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.
"Too many [] have been sedated by an oppressive environment of political correctness and risk aversion."

Replies are listed 'Best First'.
Re^8: Non closing sockets - threads
by igor1212 (Novice) on Dec 17, 2008 at 12:00 UTC
    Hello BrowserUk,

    Thanks again for your help!
    I like your code very much and will try to find out why is "Not a GLOB reference" error coming.
    If you have some more ideas, will be welcomed!

    Just an update!

    I commented out $unitID and the error has gone.

    threads->create( $peerhost = '127.0.0.1' ? \&cmdClient : \&gprsClient, # $unitId = 437918234 ? \&cmdClient : \&gprsClient, $client, $unitId )->detach;
    Best regards, Igor
      Just an update! I commented out $unitID and the error has gone.

      Gah! I cannot believe I left that in. And uncommented. Because all my test clients run locally, I had to find another way of distinguishing gprs from cmd client. So I used a hardcoded unitID.

      The two conditional lines are intended to be either/or, your system or mine.

      Does it now work? (Except for exhibiting the same failure to disconnect problem!)


      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.
        Hello :) ,

        It's working, but both clients (localhost and gprs) executes cmdClient, gprsClient is not used.

        Correction - it is all correct!
        I'll do some tests now

        Gprs clients perfectly connects to the server and keep sending data.
        Localhost client does not execute commands and just closes itself, even if there are some gprs clients connected.
        If there is no connection, for I guess 500 sec, server closes itself.
        And at last, on clients abnormal disconnection, threads remain connected.

        Servers echo:

        gprsClient [4227801339] running on 4 4227801339: Command response: data test gprsClient [4227801339] running on 5 4227801339: Command response: data second client gprsClient [4227801339] running on 6 4227801339: Command response: data third client Command Client running on 7 cmdClient [859189299] disconnected
        If you have some more suggestions, I would really appreciate!

        Regards, Igor