socket的非阻塞connect

使用通用的启用FIONBIO阻塞和禁用阻塞达到目的。

代码如下:

#if !defined(INVALID_SOCKET)
#define INVALID_SOCKET  (SOCKET)(~0)
#endif
#if !defined(SOCKET_ERROR)
#define SOCKET_ERROR            (-1)
#endif



/*
 *@brief 异步的socket connect
 *@param s socket打开的描述符,同connect的第一个参数
 *@param name 包含目标计算机的ip和端口的描述信息,同connect的第二个参数
 *@param namelen name的长度,同connect的第三个参数
 *@nTimeout 允许connet连接超时(最大可接受时间),单位毫秒。默认22秒。
 *@return 成功返回0,失败返回错误码,含义参考errno的错误码表。
 *@note 此函数调用类似于同步的connet。在使用此函数之前不要设置socket为异步,否则异步将失效。
 */
int synchronous_connect(
    SOCKET s, const struct sockaddr * name, int namelen, int nTimeout = 22000 )
{
 
    // 确保socket和目标地址信息正确
    if (INVALID_SOCKET == s || NULL == name || 0 == namelen)
    {
        return -1;
    }
    // 启动异步
    u_long nBlock(1); //为1则异步,0则取消异步
    ioctlsocket(s, FIONBIO, &nBlock);
    errno_t nRet = 0;
    // 连接
    if (SOCKET_ERROR == connect(s, name, namelen ))
    {
        fd_set fs;
        FD_ZERO(&fs);
        FD_SET(s, &fs);

        TIMEVAL timeout;
        timeout.tv_sec = nTimeout/1000;
        timeout.tv_usec = nTimeout%1000;
        int nTmp = select(s + 1, NULL, &fs, NULL, &timeout);
        if ( nTmp<=0 )
        {
            //这里通常是由于超时
            nRet = (0==nTmp?SOCKET_ERROR:errno);
            goto EXIT_POINT;
        }

        int optval = 0;
        int optlen = sizeof(optval);
        if (0 != getsockopt(s, SOL_SOCKET, SO_ERROR,
            (char*)&optval, (socklen_t*)&optlen))
        {
            // 其它错误
            nRet = errno;
            goto EXIT_POINT;
        }
        // 获取当前的socket错误状态,
        // 如果此状态为0,则表示connet成功,否则是发生了错误。
        nRet = optval;
    };
EXIT_POINT:
    nBlock = 0; // 取消异步
    ioctlsocket(s, FIONBIO, &nBlock);
    
    return nRet;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值