Non-blocking socket connect call

We know that if the socket is a TCP socket, then connect function will stimulate TCP three-way handshake, and the three-way handshake will take some time to connect the kernel timeout limit is 75 seconds, that is, if more than 75 seconds then connect It will return because of a timeout failure. However, if the remote server can not connect because of some problem, then each client will connect initiated to wait 75 will return, because the socket is blocked by default. For some online services, if certain problems with the remote server, it may lead to serious consequences in this case. Or in some cases, we do not want to live in a blocking call connect time, there are some additional tasks need to be addressed.

In this scenario, we can set the socket to non-blocking, the following code:

int flags = fcntl(c_fd, F_GETFL, 0);
if(flags < 0) {
    return 0;
}
fcntl(c_fd, F_SETFL, flags | O_NONBLOCK);

When we set the NONBLOCK socket, connect the call when, if the operation can not be completed immediately, it will return immediately connect, then it is possible to connect return -1, then the corresponding error codes need to errno, connected to judge whether continued. More complete approach is as follows:

    int sockfd = sockets::createNonblockingOrDie(_serverAddr.family());
    int ret = sockets::connect(sockfd, _serverAddr.getSockAddr());
    int savedErrno = (ret == 0) ? 0 : errno;
    switch (savedErrno) {
    case 0:
    case EINPROGRESS:
    case EINTR:
    case EISCONN:
        connecting(sockfd);
        break;
    case EAGAIN:
    case EADDRINUSE:
    case EADDRNOTAVAIL:
    case ECONNREFUSED:
    case ENETUNREACH:
        retry(sockfd);
        break;
    case EACCES:
    case EPERM:
    case EAFNOSUPPORT:
    case EALREADY:
    case EBADF:
    case EFAULT:
    case ENOTSOCK:
        LOG_ERROR << "connect error in Connector::startInLoop " << savedErrno;
        sockets::close(sockfd);
        break;
    default:
        LOG_ERROR << "Unexpected error in Connector::startInLoop " << savedErrno;
        sockets::close(sockfd);
        break;
    }

Problem with using non-blocking connect Note that: immediately establish the connection (for example, client and server on the same machine) 1. is likely to call connect, must deal with this situation. 2. Posix define two related and select non-blocking connect provisions: - When connection is successfully established, socket descriptor becomes writable. (When the connection is established, the write buffer is free, it is possible to write) - when the connection establishment fails, socket descriptor is both readable and writable. (Due to a fault pending, so readable and writeable) specific code as follows:

void Connector::handleWrite() {
    if (_state == CONNECTING) {
        int sockfd = removeAndResetChannel();
        int err = sockets::getSocketError(sockfd);
        if (err) {
            LOG_WARN << "Connector::handleWrite - SO_ERROR = "
                << err << " " << strerror_tl(err);
            retry(sockfd);
        } else if (sockets::isSelfConnect(sockfd)) {
            LOG_WARN << "Connector::handleWrite - Self connect";
            retry(sockfd);
        } else {
             setState(CONNECTED);
             if (_connected) {
                _newConnectionCallback(sockfd);
             } else {
                 sockets::close(sockfd);
             }
        }
    } else {
        assert(_state == DISCONNECTED);
    }
}

Original: Large columns  non-blocking socket connect call


Guess you like

Origin www.cnblogs.com/wangziqiang123/p/11652242.html