天天看点

linux网络编程-----非阻塞connect

libevent在内部由于使用io多路复用函数进行的事件监控,所以它所有的io读写操作都是非阻塞的,换句话说,libevent提供的接口函数evconnlistener_new_bind()和bufferevent_socket_connect()在内部使用socket创建套接字,会默认将其变为非阻塞(使用fcntl可以实现)。

比较特殊的就是客户端的connect函数,因为套接字变为非阻塞,所以connect会立即返回,这就可能出现以下三种情况

  • 连接立即建立,返回0
  • 正在进行三路握手,返回-1,errno设置为EINPROGRESS
  • 连接失败,返回-1,errno不为EINPROGRESS

非阻塞的connect可以节省三路握手的时间,可以运行其它的任务,不需要等待三路握手完成。

所以判断什么时候连接建立完成是很重要的,判断的依据是套接字的可读/可写状态

  • 当连接成功建立时,描述符变为可写
  • 当连接建立遇到错误时,描述符变为既可读又可写

这两个规则很好理解,

  • 当连接成功建立,tcp的缓冲区为空,客户端就可以使用send/write等io函数向套接字描述符写入数据,就是说描述符变为可写
  • 当连接建立失败,tcp的缓冲区仍然可写,但是因为出现错误,所以缓冲区中存在着连接错误信息,所以既可读又可写

有以下几种方法可以达到对connect连接的判断

  • 使用select对客户端套接字进行监听,同时设置超时时长。这种方法主要用于减少connect默认的超时时长,当select返回后,可以判断套接字描述符是否处在读/写事件集中。
  • 既然libevent是统一事件源,所以连接的建立也是一个事件,将套接字描述符添加到event监控中,当可读/可写时就可以判断连接情况
  • 上述两种方法都可以在io多路复用函数返回后通过getsockopt获取套接字SO_ERROR选项,当结果为0时表示连接建立,否则失败
/* 结果存入error中 */
getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &len);
           

继续阅读