in reply to Re^2: tcp server (bidirectional)
in thread tcp server (bidirectional)
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:
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.
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:
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.
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.)
|
|---|