I have this code segment that is designed to connect to a server using a socket connection. However if it can not connect to the server within a certain amount of time I would like it to stop trying. I tried to do this with this nonblocking socket and the select command but select is always returning 1 indicating that the server exists when nothing exists at the address I give it. Any Ideas?
SOCKET tcp_client( char *hname, char *sname ) {
fd_set fdset;
struct sockaddr_in peer;
SOCKET s;
FD_ZERO(&fdset);
// FD_SET(STDIN, &fdset);
FD_SET(s, &fdset);
errno=1;
struct timeval tv;
tv.tv_sec = 15;
set_address( hname, sname, &peer, "tcp" );
s = socket( AF_INET, SOCK_STREAM, 0 );
int n = 1;
fcntl(s, F_SETFL, O_NONBLOCK);
if ( !isvalidsock( s ) )
{
printf("Socket Call Failed: %s\n", strerror(errno));
return(0);
}
int x = 0;
int status = connect( s, ( struct sockaddr * )&peer, sizeof( peer ) );
if(status < 0) {
printf("Status: %i\n", status);
}
int retVal = select(s+1, &fdset, NULL, NULL, &tv);
printf("retVal: %i\n", retVal);
if (retVal == 1) {
int so_error;
socklen_t slen = sizeof so_error;
getsockopt(s, SOL_SOCKET, SO_ERROR, &so_error, &slen);
if (so_error == 0) {
printf("work\n");
x =1;
} else {
printf("fail\n");
x = 0;
}
} else {
printf("noSocks\n");
}
if (x ==0 )
{
printf("Connect Failed: %s\n", strerror(errno));
L("libOnexc: Connect to socket failed");
close(s);
return(0);
}
return s;
}
The select function returns the total number of socket handles that are ready and contained in the fd_set structures, zero if the time limit expired, or SOCKET_ERROR if an error occurred. If the return value is SOCKET_ERROR, WSAGetLastError can be used to retrieve a specific error code.
The default mode of socket calls is blocking. A blocking call does not return to your program until the event you requested has been completed.
We set a flag on a socket which marks that socket as non-blocking. This means that, when performing calls on that socket (such as read and write ), if the call cannot complete, then instead it will fail with an error like EWOULDBLOCK or EAGAIN . To mark a socket as non-blocking, we use the fcntl system call.
One problem I see is that you stick s in the fdset before you have created the socket. You need to do the
FD_SET(s, &fdset);
after you've created the socket because s is just an integer and so will not be the right value until after the call to socket().
EDIT
Like this:
.
.
.
SOCKET s;
errno=1;
struct timeval tv;
tv.tv_sec = 15;
set_address( hname, sname, &peer, "tcp" );
s = socket( AF_INET, SOCK_STREAM, 0 );
int n = 1;
fcntl(s, F_SETFL, O_NONBLOCK);
if ( !isvalidsock( s ) )
{
printf("Socket Call Failed: %s\n", strerror(errno));
return(0);
}
FD_ZERO(&fdset);
FD_SET(s, &fdset); // don't put socket in set until it is actually created
You need to check whether the socket is ready for writing (the second fd_set *
argument to select), not reading (the first one).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With