Reputation: 6255
From recent study, I came to the understanding that if you wanted to do a nonblocking socket connect, you could set your socket to nonblocking mode, then use select()
with your socket added to the writefds
argument.
Why, then, in this simplified example, does select()
unblock early and leave a state stating that my unconnected socket is writable when I haven't even performed a connect, let alone had a peer accept the connection?
#include <iostream>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <unistd.h>
#include <cerrno>
#include <cstring>
class SafeSocket
{
public:
/** Ctor.
* Creates a nonblocking socket at the specified IP in the AF_INET family and
* at a dynamic port.
*/
SafeSocket( const std::string& ip )
{
in_addr_t host_ip = inet_network( ip.c_str() );
if ( ( socket_ = socket( AF_INET, SOCK_STREAM, 0 ) ) < 0 )
{
std::cout << "socket() failed: " << errno << " " << strerror( errno )
<< std::endl;
socket_ = -1;
}
sockaddr_in si;
memset( &si, 0, sizeof( si ) );
si.sin_family = AF_INET;
si.sin_port = 0; // Dynamic port
si.sin_addr.s_addr = htonl( host_ip );
if ( bind( socket_, (sockaddr*)&si, sizeof si ) )
{
std::cout << "bind() failed: " << errno << " " << strerror( errno )
<< std::endl;
close( socket_ );
socket_ = -1;
}
// Make the socket do nonblocking connect().
int flags = fcntl( socket_, F_GETFL, 0 );
fcntl( socket_, F_SETFL, flags | O_NONBLOCK );
}
~SafeSocket()
{
if ( socket_ >= 0 )
{
shutdown( socket_, SHUT_RDWR );
close( socket_ );
}
}
operator int() const
{
return socket_;
}
private:
int socket_;
};
int main( int argc, char* argv[] )
{
SafeSocket s( "127.0.0.100" );
std::cout << "Created socket " << s << std::endl;
fd_set readFds;
fd_set writeFds;
FD_ZERO( &readFds );
FD_ZERO( &writeFds );
FD_SET( s, &writeFds );
timeval timeout = { 5, 0 };
if ( -1 == select( s+1, &readFds, &writeFds, NULL, &timeout ) )
{
std::cout << "select() failed: " << errno << " " << strerror( errno )
<< std::endl;
}
if ( FD_ISSET( s, &writeFds ) )
{
std::cout << s << " is writable!" << std::endl;
}
return 0;
}
Output:
>g++ --version
g++ (GCC) 4.8.3 20140911 (Red Hat 4.8.3-7)
Copyright (C) 2013 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
>g++ -g main.cpp
>
>./a.out
Created socket 3
3 is writable!
Upvotes: 0
Views: 557
Reputation: 249133
select()
tells you when a socket is ready for the next action. In this case, it is ready to call connect()
.
Of course, calling select()
on a brand new socket is unnecessary. Most applications wouldn't do that.
Upvotes: 1