in reply to Re: tcp server (bidirectional)
in thread tcp server (bidirectional)

Hello BrowserUk,

Thanks for your help!
Yes, this script will update MySQL database with gps data.

This is great with additional listening socket, but server still needs to receive some data from the client to respond him with a command, right?
I need to be able to send command to connected client without waiting his data.

With your version, old connections still remains opened and does not clean themselves.
When gps device reconnects to the server, it uses a different IP and port No., maybe is this the cause !?

Thanks again!

Igor V.

Replies are listed 'Best First'.
Re^3: tcp server (bidirectional)
by BrowserUk (Patriarch) on Dec 06, 2008 at 21:47 UTC
    With your version, old connections still remains opened and does not clean themselves.

    I cannot argue authoratatively with you as I do not have the device is question (nor possibly your OS), but on the basis of logic, that doesn't make much sense.

    Starting from the point where there is an established connection between the GPS device and the server, under what circumstances would it decide to reconnect? I see two possibilities:

    1. It attempts to write its regular data packet to the socket and gets an error indicating that the connection has 'gone away', and so it decides to establish a new connection.

      Under these circumstances, the readline at the server end will fail returning undef, the while loop will end.

      The server will close the socket, and fall off the end of the (detached) thread proc and the thread will self-terminate.

      It is possible that the tcpip stack will hold the socket open (in a SYN_WAIT state) for a while longer, subject the the system default timeout (900 seconds?), but it will eventually timeout and be shut down.

      You might cause it to be shutdown earlier by preceding the close with an explicit shutdown $socket, 2; before the thread terminates, but it will make little or no difference to the operation of the application.

    2. The device could decide to reboot as a result of (say) a hardware induced reset, and come up unaware of the existing established connection and make a new connection (to the server's main threads accept loop).

      Under these circumstances, the previous thread may persist in the readline (recv) state for a while, seconds or minutes (again depending upon the systems default timeout values), but eventually, the readline will timeout and the (detached) thread will close the client socket and self-terminate.

      As this is a threaded server, pending and orphaned connections will not inhibit the new connection from being established and operating.


    When gps device reconnects to the server, it uses a different IP and port No., maybe is this the cause !?

    Again, I cannot argue with what you are seeing, but logic says this doesn't make sense. If the device connected with a different IP, it would be connecting to a different machine!

    Unless the server is multi-homed (of which I have no experience), but even so, it would still have to connect to a different (copy of the) server process. And how would it know what other IP to use?

    I suspect what you are seeing is that when the device reconnects, that the socket handle reported by the     print $connection; line in the main accept loop, is different. That's normal!

    When a new client connects, (even if it is the same client reconnecting), it will get a new IO::Socket::INET instance which will have a different handle to that used previously.

    Equally, if you are monitoring the port numbers used by the client connections, the server port allocated to the new connection will be different to that used by the listening socket (that's the way tcp works!), and it will often be different to the port number used by the previous client connection, even if it is inbound from the same device and connectiing to the same listening port.

    Unless you've called shutdown (at both ends, which is unlikely given the possible scenarios ), the previous port number may not get reused (even with Reuse => 1) until both ends of the old connection have either shutdown or timed out. That can take several minutes. This is normal and of no great consequence unless you are re-establishing the same connections 100s of times per second.


    This is great with additional listening socket, but server still needs to receive some data from the client to respond him with a command, right?

    Yes. As posted, outbound (server to device) transmissions will not be sent until after an inbound data message (device to server) is received. You cannot (on my system using perl and IO::Socket, at least) transmit to a socket whilst it is currently in a read state. It may be possible on other systems, but no one has ever answered my frequent questions on this to either confirm or deny that possibility. I therefore assume that it is not possible,

    My assumption (given an absence of information to the contrary), was that the device uploads data packets at regular intervals, and so the longest delay between initiating a command input and it being transmitted, is the length of time between those regular data packets.

    If this would present an unacceptable delay, there are two possibilities:

    1. Use a non-blocking socket and a select loop to ensure that you only enter a read state when there is something to be read.

      This would allow you to transmit the command immediately from any thread that has access to the client socket. It would also considerably complicate the architecture of the application.

    2. Use a timer approach to decide when to enter the read state to fetch inbound data packets.

      This would allow you to continue to monitor the command input queue and transmit commands in a timely fashion. The downside is that it requires you to know the frequency with which the device produces data packets--which must be at regular intervals.

      So, assuming that the device uploads data packets (say) every 10 seconds, and you wish to not have to wait for that duration before transmitting a command, you might modify the client thread proc along these lines:

      sub read_data { # accept data from the socket and put it on the queue my( $qin, $qout, $socket ) = @_; while ( 1 ) { ## Don't enter a read state until your pretty sure there will b +e something ## to fetch. The loop count (10) x the sleep value (1) define t +he device ## data frequency for( 1 .. 10 ) { ## if there are any commands pending, send them to the GP +S device while( my $cmd = $qin->pending ) { print $socket $cmd; } sleep 1; ## or usleep 0.1 or 0.01 etc. ## depending upon the urgency of your cmd requirements } my $data = <$socket>; last unless defined $data; print "$data"; ## Process data from connected devices $qout->enqueue( time . ' ' . $data ); } shutdown $socket, 2; close $socket; }

      In the absence of clear information about the nature of the device and communications involved, this is an imperfect formulation, but gives an idea of one way to approach the situation.

    There is a third possibility. That of setting the socket non-blocking and not using select, but I'm uncomfortable to suggest this as my own experience of trying this have had mixed results.

    (I make no claims to any great expertise in tcp. I tend to just stick to whatever works for me on my platform. YMMV.)


    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.