现在的位置: 首页 > 综合 > 正文

也谈linux下socket的connect超时

2013年10月31日 ⁄ 综合 ⁄ 共 1723字 ⁄ 字号 评论关闭

今天写程序,涉及到socket的通信,就把以前写的一个socket通信代码拿过来用。然后就碰到了一个当时感觉到很奇怪的问题,当时的想法是:见鬼了,为什么以前用的好好的代码
怎么突然就不能用了呢?
  代码的流程是这样的
  1 建立一个socket
  2 设置socket为非阻塞
  3 connect
  4 把socket放到一个fd_set中
  5 select 这个socket,监视可写事件
  6 判断是否超时或者连接成功

  代码如下---------------------------------------------------------------------
  struct sockaddr_in servAddr;
 servAddr.sin_port = htons(port);
 servAddr.sin_family = AF_INET;
 inet_aton(servIp,&servAddr.sin_addr);
 //设置socket为非阻塞
 unsigned long ul = 1;
 int rm = ioctl(this->m_socket,FIONBIO,&ul);
 if(rm == -1)
 {
  //ioctl failed
  return -1;
 }
 if(connect(this->m_socket,(sockaddr*)&servAddr,sizeof(sockaddr)) == 0)
 {
  //connect success
  return 0;
 }
 
 if(errno != EINPROGRESS)
 {
  return -1;
 }
 log_debug("%s",strerror(errno));
 //检测socket是否可写
 fd_set writeSet,readSet;
 FD_ZERO(&writeSet);
 FD_SET(this->m_socket,&writeSet);
 int num = select(this->m_socket + 1,NULL,&writeSet,NULL,tv);
 if(num > 0)
 {
  if(FD_ISSET(this->m_socket,&writeSet))
  {
   //设置socket为阻塞
   ul = 0;
   ioctl(this->m_socket,FIONBIO,&ul);
   return 0;
  }
 }

 首先说一下这段代码的执行结果:当连接一个并不存在的socket时,select总是返回连接成功

 按照这个流程,这段代码的依据就是当非阻塞时,connect立刻返回-1,同时errno设置为EINPROGRESS。然后再检测socket是否可写,如果可写了,说明
 socket已经建立的连接,这个时候select的会在write fd_set中把socektfd置位,同时返回,这个时候判断select的返回值和用FD_ISSET宏来判断是否socketfd
 是否已经被置位来判断是否连接成功。注意:所有的这一切都是建立在 “如果一个socket建立了连接,那么这个socket是可写的”,这看起来没有错,但是关键是,如果
 连接不成功,select是否会判断socket为可写的呢?我们知道,当连接被关闭时,select仍然判断socket是可读的。难道即使socket连接不成功,select仍然返回
 可写吗?
    经过试验,真的是这样的。
 所以,上面的代码如果在异常情况下仍然正常工作,在select返回时须作如下修改:
 if(FD_ISSET(this->m_socket,&writeSet))
  {
   int error = 0;
   int errLen = sizeof(error);
   if(getsockopt(this->m_socket,SOL_SOCKET,SO_ERROR,&error,(socklen_t*)&errLen) < 0)
   {
    return -1;
   }
   if(error != 0)
   {
    return -1;
   }
   //设置socket为阻塞
   ul = 0;
   ioctl(this->m_socket,FIONBIO,&ul);
   return 0;
  }

抱歉!评论已关闭.