为什么非阻塞套接字在connect()或accept()之前是可写的?

时间:2017-12-02 00:56:07

标签: c++ linux sockets select

从最近的研究中,我发现如果你想进行非阻塞套接字连接,可以将套接字设置为非阻塞模式,然后使用today将套接字添加到select()参数。

为什么,在这个简化的示例中,writefds提前解除锁定并留下一个状态,表明当我甚至没有执行连接时,我的未连接套接字是可写的,更不用说让对等方接受连接?

select()

输出:

#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;
}

1 个答案:

答案 0 :(得分:1)

select()告诉您套接字何时准备好进行下一个操作。在这种情况下,可以调用connect()

当然,在全新的套接字上调用select()是不必要的。大多数应用程序都不会这样做。