Beefy Boxes and Bandwidth Generously Provided by pair Networks
laziness, impatience, and hubris

Remote TCP Port Connection Monitoring

by w3ntp (Beadle)
on Dec 10, 2003 at 16:27 UTC ( #313766=perlquestion: print w/replies, xml ) Need Help??

w3ntp has asked for the wisdom of the Perl Monks concerning the following question:

I have a TCP Client Application on the other side of a firewall that communicates with a local TCP Server Application. The Firewall is setup to block all traffic except this TCP traffic over its specific port. I have found that if the TCP connection on the other side of the firewall is abruptly terminated (yanked cable), the local TCP connection remains in the ESTABLISHED state forever. So what I am trying to do is find out if the remote client is up; possibly by sending a dummy TCP ack or some connection scheme to a client. Unfortunately, the local netstat and lsof commands do not detect the dropped TCP session. Any ideas or thoughts? thanks w3ntp

Replies are listed 'Best First'.
Re: Remote TCP Port Connection Monitoring
by tachyon (Chancellor) on Dec 10, 2003 at 17:03 UTC

    If what you are trying to test is a server application that can handle more than one simultaneous connection then simply trying to connect a socket, seeing if it works and then disconnecting is all you need to do (you need 2 connections to handle the case when the target is up) We use this when we just want a very basic test.

    use IO::Socket::INET; print test_port_simple( '', 80, 1234, 'speak!' ), $/; print test_port_simple( '', 81, 1234, 'speak!' ); sub test_port_simple { my ( $server, $port, $timeout, $verbose ) = @_; return "ERR - No server supplied" unless $server; return "ERR - No port supplied" unless $port; $timeout ||= 10; print "Simple testing $server:$port\n" if $verbose; my $sock = IO::Socket::INET->new( PeerAddr => $server, PeerPort => $port, Proto => 'tcp', Timeout => $timeout, ReuseAddr=> 1, ReusePort=> 1, ); my $res = $sock ? 'OK' : "ERR - Could not connect socket on port $ +port"; $sock->close() if $sock; return $res; } __DATA__ Simple testing OK Simple testing ERR - Could not connect socket on port 81

    This proves the connectivity, not the functionality. We have had disk I/O issues in the past that left server processes in memory (and handling connections) but dyfunctional in any real sense. If your test target has an established protocol you can make the test far more reliable by printing a line to the socket and checking for the expected response.

    sub test_port_detailed { my ( $server, $port, $timeout, $verbose ) = @_; # testing on port 25 requires sending (your) valid maildomain my $MAILDOMAIN = ''; return "ERR - No server supplied" unless $server; return "ERR - No port supplied" unless $port; $timeout ||= 10; print "Detail testing $server:$port\n" if $verbose; my $sock = IO::Socket::INET->new( PeerAddr => $server, PeerPort => $port, Proto => 'tcp', Timeout => $timeout, ReuseAddr=> 1, ReusePort=> 1, ); unless ( $sock ) { undef $sock; return "ERR - Could not connect socket on port $port"; } my $errors = ''; # OK so we have a socket but can we use it as expected # depending on the protocol we apply different tests.... if ( $port == 21 ) { my $server = <$sock>; if ( $server ) { print $sock "USER anonymous\015\012"; $server = <$sock>; $errors .= "No USER response from FTP server\n" unless $se +rver; print $sock "QUIT\015\012"; } else { $errors .= "No handshake sent from FTP server\n"; } } elsif ( $port == 25 ) { my $server = <$sock>; if ( $server ) { print $sock "HELO $MAILDOMAIN\015\012"; $server = <$sock>; $errors .= "No HELO response from SMTP server\n" unless $s +erver and $server =~ m/^250/; print $sock "QUIT\015\012"; } else { $errors .= "No handshake sent from SMTP server\n" } } elsif ( $port == 80 ) { print $sock "GET / HTTP/1.0\015\012\015\012"; my $server = <$sock>; $errors .= "Unexpected response from HTTP server\n" unless $se +rver and $server =~ m/^HTTP/; } elsif ( $port == 110 ) { my $server = <$sock>; if ( $server ) { $errors .= "No OK sent by POP3 server\n" unless $server =~ + m/OK/i; print $sock "USER nobody\015\012"; $server = <$sock>; print $sock "PASS wrong_password\015\012"; $server = <$sock>; $errors .= "Failed to get expected ERR response\n" unless +$server and $server =~ m/ERR/i; print $sock "QUIT\015\012"; } else { $errors .= "No handshake sent from POP3 server\n"; } } elsif ( $port == 3128 ) { print $sock "GET http://$server/ HTTP/1.0\015\012\015\012"; my $server = <$sock>; $errors .= "Unexpected response from SQUID PROXY server\n" unl +ess $server and $server =~ m/^HTTP/i; } else { # we don't have a detail test but do have a socket so this is +a NOP } $sock->close(); return $errors ? "ERR - $errors" : 'OK'; }

    Note you probably won't be able to use the ReusePort flag on win 32 - SO_REUSEPORT will probably be undefined, so just comment that line out.



      Actually, its not the Server side I am interested in, but the Client side. The client is on the other side of the firewall and I want to make sure connectivity to the client is up. The problem is how to connect to a TCP client?? thanks W3ntp

        A client does not accept connections, that is why it is called a client not a server....



TCP keep-alives
by sleepingsquirrel (Hermit) on Dec 11, 2003 at 00:45 UTC
    Sounds like you might be interested in TCP keep-alives. From the Sockets-FAQ...
    8. Why does it take so long to detect that the peer died?

    Because by default, no packets are sent on the TCP connection unless there is data to send or acknowledge.

    So, if you are simply waiting for data from the peer, there is no way to tell if the peer has silently gone away, or just isn't ready to send any more data yet. This can be a problem (especially if the peer is a PC, and the user just hits the Big Switch...).

    One solution is to use the SO_KEEPALIVE option. This option enables periodic probing of the connection to ensure that the peer is still present. BE WARNED: the default timeout for this option is AT LEAST 2 HOURS. This timeout can often be altered (in a system-dependent fashion) but not normally on a per-connection basis (AFAIK).

    RFC1122 specifies that this timeout (if it exists) must be configurable. On the majority of Unix variants, this configuration may only be done globally, affecting all TCP connections which have keepalive enabled. The method of changing the value, moreover, is often difficult and/or poorly documented, and in any case is different for just about every version in existence.

    If you must change the value, look for something resembling tcp_keepidle in your kernel configuration or network options configuration.

    If you're sending to the peer, though, you have some better guarantees; since sending data implies receiving ACKs from the peer, then you will know after the retransmit timeout whether the peer is still alive. But the retransmit timeout is designed to allow for various contingencies, with the intention that TCP connections are not dropped simply as a result of minor network upsets. So you should still expect a delay of several minutes before getting notification of the failure.

    The approach taken by most application protocols currently in use on the Internet (e.g. FTP, SMTP etc.) is to implement read timeouts on the server end; the server simply gives up on the client if no requests are received in a given time period (often of the order of 15 minutes). Protocols where the connection is maintained even if idle for long periods have two choices:

    1. use SO_KEEPALIVE
    2. use a higher-level keepalive mechanism (such as sending a null request to the server every so often).

    For perl, I think turning on keep-alives would look something like...
    use IO::Socket; $sock = IO::Socket::INET->new(Listen => 5, LocalAddr => 'localhost', KeepAlive => 1, LocalPort => 1234, Reuse => 1, Proto => 'tcp');
    You might also find this post interesting. If your OS is Linux, you set the keep-alive parameters by editing the files...


Re: Remote TCP Port Connection Monitoring
by jaga (Initiate) on Dec 10, 2003 at 19:05 UTC
    I *highly* recommend testing more than just a TCP connection because it is not rare that a system looses the ability to spawn a new process. If this happens your TCP connection test work may succeed but your application may still be failing. The 2nd of tachyon's examples is the way to go. Just my 2c. --jaga
Re: Remote TCP Port Connection Monitoring
by melora (Scribe) on Dec 10, 2003 at 19:40 UTC
    Well, this may be irrelevant, but you might want to have a look at Network Duplex speed test where ping is used to check on connections.   Just a thought.
      Hi, Thanks for the thought. The problem is that ICMP packets are blocked, so the routine would not work. W3ntp
Re: Remote TCP Port Connection Monitoring
by zakzebrowski (Curate) on Dec 10, 2003 at 21:20 UTC
    Ensure that you have timeout's for your tcp session. Moving up to the jdbc level (java, ew) , mysql's jdbc driver had a problem on the low end box we were using, because it was taking greater than 30 seconds to get to the server and back. try'ing and catch'ing the tcp timeout exception helped on the client end... but you also need to make sure on the server end that the server shuts down inactive clients in a timely manor, or the server will think that there are a lot more open sessions then their actually is, taking up valuable server resources...


Log In?

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://313766]
Approved by tachyon
Front-paged by broquaint
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others scrutinizing the Monastery: (2)
As of 2023-10-01 22:37 GMT
Find Nodes?
    Voting Booth?

    No recent polls found