非阻塞模式下connect的使用方式

客户端调用connect发起对服务器的socket的连接请求:

阻塞模式:

如果客户端socket描述符为阻塞模式则会一直阻塞到连接建立或者连接失败(注意阻塞模式的超时时间可能为75秒到几分钟之间)。

非阻塞模式:

如果客户端socket描述符为阻塞模式则会一直阻塞到连接建立或者连接失败(注意阻塞模式的超时时间可能为75秒到几分钟之间)。
判断连接成功没有的方法:
1.调用getpeername获取对端的socket地址.如果getpeername返回ENOTCONN,表示连接建立失败,然后用SO_ERROR调用getsockopt得到套接口描述符上的待处理错误;
2.调用read,读取长度为0字节的数据.如果read调用失败,则表示连接建立失败,而且read返回的errno指明了连接失败的原因.如果连接建立成功,read应该返回0;
  3.再调用一次connect.它应该失败,如果错误errno是EISCONN,就表示套接口已经建立,而且第一次连接是成功的;否则,连接就是失败的。

udp的情况

  对于无连接的socket类型(SOCK_DGRAM),客户端也可以调用connect进行连接,此连接实际上并不建立类似SOCK_STREAM的连接,而仅仅是在本地保存了对端的地址,这样后续的读写操作可以默认以连接的对端为操作对象。
  以下贴一段代码,该代码来源为腾讯开源的MSEC服务器的代码:显示正确的非阻塞使用方法  
  

int MtFrame::connect(int fd, const struct sockaddr *addr, int addrlen, int timeout)
{
    MtFrame* mtframe = MtFrame::Instance();
    utime64_t start = mtframe->GetLastClock();
    MicroThread* thread = mtframe->GetActiveThread();
    utime64_t now = 0;

    int n = 0; 
    mt_hook_syscall(connect);
    while ((n = mt_real_func(connect)(fd, addr, addrlen)) < 0)
    {
        now = mtframe->GetLastClock();
        if ((int)(now - start) > timeout)
        {
            errno = ETIME;            
            return -1;
        }
        // 此处为第二次调用connect函数的出口,表明连接连接成功。
        if (errno == EISCONN)   // ÒÑÁ¬½Ó, ·µ»Ø³É¹¦
        {
            return 0;
        }

        if (errno == EINTR) {
            continue;
        }

        if (!((errno == EAGAIN) || (errno == EINPROGRESS))) {
            MTLOG_ERROR("connect failed, errno: %d", errno);
            return -2;
        }

        EpollerObj epfd;
        epfd.SetOsfd(fd);
        epfd.EnableOutput();
        epfd.SetOwnerThread(thread);
        if (!mtframe->EpollSchedule(NULL, &epfd, timeout)) {
            return -3;
        }
        //此处返回后外层循环会继续 重新调用一次 connect。
    }

    return n;
}

你可能感兴趣的:(网络编程)