connect调用超时的实现方式

  第二种更通用的、使connect调用超时的方法是使套接字成为无阻塞的,然后用select等待它完成。这种方法避免了使用alarm时遇到的很多问题,但我们必须承认,即使是在UNIX实现中,这种方法还是存在很多可移植性问题。

int main(int argc, char **argv)

{

  fd_set rdevents;

  fd_set wrevents;

  fd_set exevents;

  struct sockaddr_in peer;

  struct timeval tv;

  SOCKET s;

  int flags;

  int rc;

  INIT();

  set_address(argv[1], argv[2], &peer, "tcp");

  s=socket(AF_INET,SOCK_STREAM,0);

  if(!isvalidsock(s))

    error(1,errno,"socket call failed");

  if((flags=fcntl(s,F_GETFL,0)) <0)

    error(1,errno,"fcntl(F_GETFL) failed");

  if((rc = connect(s,(struct sockaddr *)&peer,

    sizeof(peer))) && errno != EINPROGRESS)

    error(1,errno,"connect failed");

  if(rc == 0)

  {

    if(fcntl(s,F_SETFL,flags) < 0)

      error(1,errno, "fcntl(restore flags) failed");

    client(s,&peer);

    EXIT(0);

  }

  FD_ZERO(&rdevents);

  FD_SET(s,&rdevents);

  wrevents = rdevents;

  exevents = rdevents;

  tv.tv_sec = 5;

  tv.tv_usec = 0;

  rc = select(s+1, &rdwvents, &wrevents, &exevents, &tv);

  if(rc < 0)

    error(1,errno, "select failed");

  else if(rc == 0)

    error(1,0, "connect timed out\n");

  else if(isconnected(s,&rdevents, &wrevents, &exevents))

  {

    if(fcntl(s, F_SETFL, flags) < 0)

      error(1 errno, "fcntl(restore flags) failed");

    client(s,&peer);

  }

  else

    error(1,errno, "connect failed");

  EXIT(0);

}

 

int isconnected(SOCKET s,fd_set *rd, fd_set *wr, fd_set *ex)

{

  int err;

  int len=sizeof(err);

  errno = 0;

  if(!FD_ISSET(s, rd) && !FD_ISSET(s, wr))

    return 0;

  if(getsockopt(s,SOL_SOCKET,SO_ERROR,&err,&len) < 0)

    return 0;

  errno = err;

  return err == 0;

}

posted @ 2014-12-23 16:44  苦逼码农2014  阅读(209)  评论(0编辑  收藏  举报