This question is very similar (or almost identical) to In a non blocking socket connect, select() always returns 1; however, I can't seem to find where my code is faltering.
I am using non-blocking sockets and want to use select() when connecting a client to a server to check for timeout/success. The problem is select() is always returning 1 almost immediately, even when I don't even have the server running and there is nothing to connect to. Thanks in advance for the help, code snippet is as follows:
//Loop through the addrinfo structs and try to connect to the first one we can
for(p = serverinfo; p != NULL; p = p->ai_next) {
if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1)
{
//We couldn't create the socket, try again
perror("client: socket");
continue;
}
//Set the socket to non-blocking
int flags = fcntl(sockfd, F_GETFL, 0);
fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
if (connect(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
//The error was something other than non-block/in progress, try next addrinfo
if(errno != EINPROGRESS)
{
close(sockfd);
perror("client: connect");
continue;
}
fd_set write_fds;
FD_ZERO(&write_fds); //Zero out the file descriptor set
FD_SET(sockfd, &write_fds); //Set the current socket file descriptor into the set
//We are going to use select to wait for the socket to connect
struct timeval tv; //Time value struct declaration
tv.tv_sec = 5; //The second portion of the struct
tv.tv_usec = 0; //The microsecond portion of the struct
//DEBUG: This is ALWAYS 1
int select_ret = select(sockfd + 1, NULL, &write_fds, NULL, &tv);
cout << select_ret << endl;
//Check return, -1 is error, 0 is timeout
if(select_ret == -1 || select_ret == 0)
{
//We had an error connecting
cout << "Error Connecting\n";
close(sockfd);
continue;
}
}
//We successfully connected, break out of loop
break;
}
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.
To mark a socket as non-blocking, we use the fcntl system call. Here's an example: int flags = guard(fcntl(socket_fd, F_GETFL), "could not get file flags"); guard(fcntl(socket_fd, F_SETFL, flags | O_NONBLOCK), "could not set file flags"); Here's a complete example.
When you make a socket non-blocking by calling setblocking(0) , it will never wait for the operation to complete. So when you call the send() method, it will put as much data in the buffer as possible and return. As this is read by the remote connection, the data is removed from the buffer.
By default, TCP sockets are placed in a blocking mode. This means that the control is not returned to your program until some specific operation is complete. For example, if you call the connect() method, the connection blocks your program until the operation is complete.
What do you expect select() to return? Consider that select() is normally used to wait for multiple file descriptors - if you were connecting two, how would you know which one succeeded/failed based purely on the return value of select? You wouldn't, obviously.
Which is why select() just tells you which file descriptors have changed in some way, and you're supposed to determine independently what that was. In the case of connect(), you should call getsockopt() to retrieve the result of the connection attempt. See this answer where I explain how to do a non-blocking connect().
When connecting in non-blocking mode and select() indicates the connection is writeable, you are then supposed to call connect() again. Doing so will return -1 with errno == ECONNRESET or whatever it is.
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