学习网络编程的一些实用技巧和细节

https://blog.csdn.net/analogous_love/article/details/60761528

非阻塞的的connect()函数如何编写

1. 创建socket时,将socket设置成非阻塞模式

2. 接着调用connect()进行连接,如果connect()能立即连接成功,则返回0;如果此刻不能立即连接成功,则返回-1(windows上返回SOCKET_ERROR也等于-1),这个时候错误码是WSAEWOULDBLOCK(windows平台),或者是EINPROGRESS(linux平台),表明立即暂时不能完成。

3. 接着调用select()函数在指定的时间内检测socket是否可写,如果可写表明connect()连接成功。

需要注意的是:linux平台上connect()暂时不能完成返回-1,错误码可能是EINPROGRESS,也可能是由于被信号给中断了,这个时候错误码是:EINTR。这种情况也要考虑到;而在windows平台上除了用select()函数去检测socket是否可写,也可以使用windows平台自带的函数WSAAsyncSelect或WSAEventSelect来检测。

/** 
 *@param timeout 连接超时时间,单位为秒
 *@return 连接成功返回true,反之返回false
 **/
bool CSocket::Connect(int timeout)
{
    //windows将socket设置成非阻塞的方式
    unsigned long on = 1;
    if (::ioctlsocket(m_hSocket, FIONBIO, &on) < 0)
        return false;
 
    //linux将socket设置成非阻塞的方式
    //将新socket设置为non-blocking
    /*
    int oldflag = ::fcntl(newfd, F_GETFL, 0);
    int newflag = oldflag | O_NONBLOCK;
    if (::fcntl(m_hSocket, F_SETFL, newflag) == -1)      
        return false;
    */
 
    struct sockaddr_in addrSrv = { 0 };
    addrSrv.sin_family = AF_INET;
    addrSrv.sin_addr = htonl(addr);
    addrSrv.sin_port = htons((u_short)m_nPort);
    int ret = ::connect(m_hSocket, (struct sockaddr*)&addrSrv, sizeof(addrSrv));
    if (ret == 0)//返回0 直接ok了
        return true;
 
    //windows下检测WSAEWOULDBLOCK
    if (ret < 0 && WSAGetLastError() != WSAEWOULDBLOCK)
        return false;
 
 
    //linux下需要检测EINPROGRESS和EINTR
    /* //小于0 需要进行错误码的检验   因为已经发起了三次握手  需要时间呢 RTT时间的存在   所以后面需要select再次进行检验
    if (ret < 0 && (errno != EINPROGRESS || errno != EINTR))
        return false;
    */
 
    fd_set writeset;
    FD_ZERO(&writeset);
    FD_SET(m_hSocket, &writeset);
    struct timeval tv;
    tv.tv_sec = timeout;
    //可以利用tv_usec做更小精度的超时设置
    tv.tv_usec = 0;
    if (::select(m_hSocket + 1, NULL, &writeset, NULL, &tv) != 1)
        return false;
 
    return true;
}

二、非阻塞socket下如何正确的收发数据

继续未完成

猜你喜欢

转载自www.cnblogs.com/zhangkele/p/10466657.html