非阻塞套接字connect

EINPROGRESS
The socket is nonblocking and the connection cannot be completed immediately. It is possible to select(2) or poll(2) for completion by selecting the socket for writing. After select(2) indicates writability, use getsockopt(2) to read the SO_ERROR option at level SOL_SOCKET to determine whether connect() completed successfully (SO_ERROR is zero) or unsuccessfully (SO_ERROR is one of the usual error codes listed here, explaining the reason for the failure).

引用man connect,对于非阻塞套接字调用connect不会立即完成,通常返回错误-1,错误码是EINPROGRESS,我们应该调用select或者poll等待套接字可写,然后使用getsockopt获取错误值,如果等于0就是连接成功。

int connect_timeout(int fd, const struct sockaddr *addr, socklen_t addrlen, 
                    int nsec, int usec)
{
    if (-1 == make_socket_nonblocking(fd))
    {
        return -1;
    }
    struct timeval timeout;
    timeout.tv_sec = nsec;
    timeout.tv_usec = usec;
    fd_set write_set;
    FD_ZERO(&write_set);
    FD_SET(fd, &write_set);
    int ret = connect(fd, addr, addrlen);
    //connect成功
    if (ret == 0)
    {
        return 0;
    }
    //开始三次握手,但并未完成
    else if (ret == -1)
    {
        //只有返回错误EINPROGRESS才继续处理
        if (errno != EINPROGRESS)
        {
            return -1;
        }
        //关心非阻塞套接字的可写状态
        int count = select(fd+1, NULL, &write_set, NULL, &timeout);
        //超过timeout还没有触发,连接超时
        if (count == 0)
        {
            return -1;
        }
        //select返回错误
        if (count == -1)
        {
            return -1;
        }
        if (FD_ISSET(fd, &write_set))
        {
            int err = 0;
            socklen_t len = sizeof(err);
            if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &len) == -1)
            {
                return -1;
            }
            //err等于0才是连接成功
            if (err != 0)
            {
                return -1;
            }
            return 0;
        }
        else
        {
            return -1;
        }
    }
}

套接字的各种实现以及非阻塞connect有移植性的问题,可以参考这篇文章非阻塞connect对于select注意问题
connect默认超时时间是75S,但是对于udp调用connect因为并不会引发三次握手,只是内核做了对端的地址和端口绑定,方便后续使用send而不需要使用sendto,connect后会立即返回是否绑定成功,所以没有必要使用这个方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值