Tutorial :tcp connect timeout (unix/windows portable)



Question:

I'm using perl (which hopefully shouldn't affect anything), but I need to know how I can set a timeout for the connect operation. The problem is I can't wait forever for the connect operation to happen. If it doesn't happen within a few seconds, I'd rather give-up and move on.

socket(my $sock, PF_INET, SOCK_STREAM, (getprotobyname('tcp'))[2]);  setsockopt($sock, SOL_SOCKET, SO_SNDTIMEO, 10); # send timeout    print "connecting...\n";  connect($sock, sockaddr_in(80,scalar gethostbyname('lossy.host.com')));  print "connected...\n";  

The problem is, if the connection to "lossy.host.com" is "lossy" or slow or anything but fast, I'd rather give up than make the user wait. (Think of it as a side-effect to a program that does something else... the user probably doesn't expect this script to communicate with a server somewhere...).

Threading Case: How would you interrupt the connect()? Would you just detach the thread and forget about it?


Solution:1

You can use fcntl to set the socket to be non-blocking, then select with a timeout waiting for it to become readable. If it doesn't become readable before the timeout, you could close it at that point.

I know how to do this in C, but not perl, otherwise I'd give you an example. The perlfunc manpage says that all of these functions exist and a cursory read seems to say they'll work like you want.

Edit: sorry, missed the part where perlfunc says they may not be available on non-Unix systems, and indeed, fcntl isn't available on win32. There is an IO::Socket library that you can use that will do the right thing on Windows though.

Here's sample code that works for me (on linux anyway):

#!/usr/bin/perl    use IO::Socket::INET;  use IO::Select;    $sock = IO::Socket::INET->new('PeerAddr' => 'lossy.host.com',                                'PeerPort' => 80,                                'Blocking' => 0 );    $sel = IO::Select->new( $sock );    @writes = $sel->can_write(10);    if ( $sock->connected ) {      print "socket is connected\n";  } else {      print "socket not connected after however long\n";      $sock->close;  }


Solution:2

You could spawn a separate thread to do it, and then do a timed wait for a result. If you don't receive a result in an appropriate amount of time, give up waiting and just let the thread continue. It will eventually time out, or you might be able to kill the thread.

To answer the initial question, I don't think there's a way to change the connect() timeout, at least not through a sockets API. On Windows, I wouldn't be surprised if there's a registry key you could change that would affect it, but I don't know what it would be.


Solution:3

If you end up doing the threaded case wherein you detach the connecting thread without killing it, beware the following: Windows only lets you have a maximum of 10 pending outgoing TCP connections (the 11th will block until one of the pending ones times out).

This was the cause of much frustration for me. I think MS put this in to prevent botnets from spreading or something. I don't think there's any way to switch it off either.


Note:If u also have question or solution just comment us below or mail us on toontricks1994@gmail.com
Previous
Next Post »