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

Hello BrowserUk,

Really thanks for your help!

I'm getting this error with your code: thread failed to start: Not a GLOB reference at tcpserver4.pl line 43 (and 83).

Old threads within the server persists for at least 10 hours
I've checked with netstat -apn | grep 8000
After tcp server is restarted they disappear

My code except this, works as it should and it immediately sends the command to the Selected client without delay.
I do include with client command data also the UnitID to whom it must send the command.
Gprs device sends gps data at minimum 10 second interval and sends sync data at a definable interval (currently at about 5 minutes)

Regards, Igor

Replies are listed 'Best First'.
Re^5: Non closing sockets - threads
by BrowserUk (Patriarch) on Dec 16, 2008 at 15:27 UTC
    Not a GLOB reference at tcpserver4.pl line 43 (and 83).

    Would you try the following changes:

    use threads qw[ yield ]; ## Why (*&^^%) isn't that exported by default +? ... threads->create( ... ); yield; sleep 1; ## insert } ...
    1. "Old threads within the server persists for at least 10 hours"

      I just don't see that effect here. No matter how I break the connection--from quitting the client cleanly to killing the client process--the while( <$client> ) loop in the server terminates immediately, and so the thread ends.

      This seems to be one of those infamous platform differences. On windows, there are timeouts for inter-character receipt, a per-byte-to-read timeout, and a total read timeout.

      Looking at the man page for SetSockOpt(), you could try using SO_RCVTIMEO to set a maximum read timeout and see if that allowed the read to terminate.

    2. " it immediately sends the command to the Selected client without delay."

      Hm. It implies that on your platform, writing to a (dup of) a socket, whilst another thread is in a read state on it, goes ahead immediately.

      That doesn't work on here. (At least for sockets as provided by IO::Socket::INET--it seem to work okay from C.)

    3. "I do include with client command data also the UnitID to whom it must send the command."

      I've been doing that too. My code (when it works:(), routes the commands using the UnitID input from the command client.


    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,

      There is still the same error, except that it waits for 1 sec and then close the client.
      I'm not sure, but does your script end the connection after it receives gprs client data or keeps waiting for next data from client.
      It must not close the client connection, except when the client has been disconnected for gprs network reasons.

      Regards, Igor

        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.