设置非阻塞socket及使connect调用超时

一般TCP建立连接过程中需要“三次握手”。在socket阻塞的情况下,connect要花一个往返时间完成,从几毫秒到几百毫秒,如果网络拥塞,或者连接的主机还没启动,则要花费更长的时间,默认时间(典型值为75秒,也可能需要更长的时间)。

可以通过将socket设置为非阻塞再用select来实现connect调用超时,步骤如下:

1.创建socket

2.设置socket为非阻塞

3.利用connect()返回值判断connect的状态(此时connect不阻塞)

4.利用select()返回值判断connect的状态

 

void main(void)

{
  int fd;
  int flags;

  struct sockaddr_in sock;

  fd = socket(AF_INET, SOCK_STREAM, 0);

  if((flags = fcntl(fd, F_GETFL, 0)) < 0){        /*查看fcntl说明(链接)*/
    perror("F_GETFL failed\n");
  }

  if(fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0){     /*设置socket为非阻塞*/
    perror("F_SETFL failed\n");
  }
  /*int t = 1;
  ioctl(fd, FIONBIO, &t);*/     /*FIONBIO为设置清除非阻塞I/O 标志*/

  fd_set rd;
  fd_set wr;
  int err;
  int len = sizeof(err);
  struct timeval tv;

  int res = connect(fd, (struct sockaddr*)&sock, sizeof(sock));
  if(0 == res){
    printf("connect \n");
    if(fcntl(fd, F_SETFL, flags) < 0){
      perror("F_SETFL failed\n");
    }
    close(fd);
    exit(0);
  }

  if(res != 0){
    perror("It have not connected temporarily\n");
  }


  FD_ZERO(&rd);
  FD_ZERO(&wr);
  FD_SET(fd, &rd);
  FD_SET(fd, &wr);

  tv.tv_sec = 20;            /*设置select超时时间*/
  tv.tv_usec = 0;

  res = select(fd + 1, &rd, &wr, NULL, &tv);
  if(res < 0)
    perror("select failed\n");
  else if(0 == res)
    perror("time out \n");
  else{
    if(FD_ISSET(fd, &wr) && FD_ISSET(fd, &rd) )
      perror("unconnect\n");
    res = getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &len);
    if(res < 0)
      perror("unconnect\n");
    if(fcntl(fd, F_SETFL, flags) < 0){
      perror("F_SETFL failed\n");
    }
  }
  close(fd);
  exit(0);
}

 

 

注:(红色代码部分)

1.如果select返回<0,则select调用错误;

2.如果select返回0,则表示建立连接超时;

3.如果select返回>0,则需要检查套接口描述符是否可读或可写;如果套接口描述符可读或可写,调用getsockopt来得到套接口上待处理的错误(SO_ERROR),如果连接建立成功,这个错误值将是0,如果建立连接时遇到错误,则这个值是连接错误所对应的errno值.

posted on 2012-08-19 17:33  Chris-Lin  阅读(1767)  评论(0编辑  收藏  举报

导航