Click to See Complete Forum and Search --> : [RESOLVED] setsockopt for connection timeout


nice_guy_mel
June 19th, 2007, 10:51 AM
Using Visual Studio 6.0 with Service Pack 6
I am creating TCP connection using the Qt (C++ Library from Trolltech) QSocketDevice class. One of it's features is to return the handle to the socket, so that I can use the handle to set certain socket options.
We recently had a customer complain because his TCP connections take too long to establish. Each one takes 20 seconds to fail. I thought there would be a setsockopt option for connection timeout, but I can't find one. The closest I could find was send timeout and receive timeout, which seems to imply that you want to control the socket's send/receive after making the connection. I want to put a timeout at the moment the socket connection is attempted. I'm not sure if many are familiar with Qt, so just imagine you're using a regular SOCKET object. If you are familiar with Qt, then here is the code I am using:

QHostAddress HostAddr;
HostAddr.setAddress("205.198.31.12");
unsigned int unPort = 10000
int nOpt = 2;
setsockopt(m_QSDevice.socket(), SOL_SOCKET, SO_RCVTIMEO, (char*)&nOpt, sizeof(int));
bConnected = m_QSDevice.connect(HostAddr, unPort);

MikeAThon
June 19th, 2007, 01:31 PM
The reason for the delay is due to the retry mechanism that TCP uses in its attempt to establish connections: TCP tries three times, with a timing back-off after each one. One explanation is here: http://www.codeguru.com/forum/showthread.php?t=424132

There is no option for setting a connection timeout. You will need to program it yourself. If you have a standard Windows GUI-style application, which infers that your sockets are non-blocking, then simply set a timer after the call to connect() and kill the connection if the timer fires before the connection completes. (You are using non-blocking sockets, aren't you?)

If this is a console-style application, using blocking sockets, then set the socket to non-blocking before the connection attempt, call connect(), set the socket into an fd_set, and then block on a call to select() with your desired timeout. If select() returns a value of zero ( 0 ), then the time limit expired before the connection could be completed. In this case, flag the error, else, the connection completed successfully so set the socket back to blocking mode and continue.

Mike

nice_guy_mel
June 19th, 2007, 02:43 PM
Thanks Mike,
QSocketDevices allow sockets to be dynamically set to block or not, so I'll give your timer idea a shot.

nice_guy_mel
June 29th, 2007, 10:11 AM
Turns out an easy solution for us was simply to set the socket to non-blocking, then make the connection. We then let the thread sleep for X seconds then check the socket to see if any bytes are available. The user is allowed to configure the wait time for the first few bytes, so they are no longer forced to wait 21 seconds. This works great for us because most of our socket connections have data coming in right away.

dog_pig_baby
July 1st, 2007, 11:58 PM
You can use this function or modify it to reduce the connection time
----------------------------------------------------------------------------------

#define MAX_SIZE 256
#define ERROR_RETURN(x) return x;
#define CHECK_FUNCTION(fun) if ( 0 != fun ) return false;
#define CHECK_FUNCTION2(fun,val,out) if ( ( out = fun) == val ) return false;
#define FREE(x) if ( x != NULL ) { free(x); x = NULL;}


int ConnectAsyn(SOCKET s,
const char* ip,
unsigned short port,
timeval* pTimeVal )
{
unsigned long ul = 1;
if ( SOCKET_ERROR == ioctlsocket( s, FIONBIO, (unsigned long*)&ul) )
ERROR_RETURN( ConnectSyn( s,ip,port ) );

if ( 0 == ConnectSyn( s,ip,port ) )
{
ul = 0;
if ( SOCKET_ERROR == ioctlsocket( s, FIONBIO, (unsigned long*)&ul) )
ERROR_RETURN( -1 );

return 0;
}

fd_set fdread,fdwrite;
int ret = 0;
FD_ZERO( &fdread );
FD_ZERO( &fdwrite );
FD_SET( s, &fdread);
FD_SET( s, &fdwrite);

if (( ret = select( 0, &fdread, &fdwrite, NULL,pTimeVal )) == SOCKET_ERROR )
{
ul = 0;
if ( SOCKET_ERROR == ioctlsocket( s, FIONBIO, (unsigned long*)&ul) )
ERROR_RETURN( -1 );

ERROR_RETURN( WSAGetLastError() );
}

if ( ret > 0)
{
if ( FD_ISSET(s, &fdwrite) )
{
ul = 0;
return ( SOCKET_ERROR == ioctlsocket( s, FIONBIO, (unsigned long*)&ul) )? -1: 0;
}
}

ul = 0;
ioctlsocket( s, FIONBIO, (unsigned long*)&ul);
ERROR_RETURN( -1 );
}

dog_pig_baby
July 2nd, 2007, 12:00 AM
int ConnectSyn( SOCKET s,
const char* ip,
unsigned short port)
{
SOCKADDR_IN addr;
addr.sin_family = AF_INET;
addr.sin_port = htons( port );
addr.sin_addr.s_addr = inet_addr( ip );

return connect( s,(struct sockaddr*)&addr,sizeof( SOCKADDR_IN ) );
}


I am sorry