怎么实现带超时功能的 connect 函数

来源:互联网 发布:淘宝为啥登不上去 编辑:程序博客网 时间:2024/04/30 04:44

怎么实现带超时功能的 connect 函数

原理:
今天仔细看了 man connect,明白了错误的原因:
EINPROGRESS
The  socket  is  non-blocking and the connection
cannot be completed immediately.  It is possible
to   select(2)  or  poll(2)  for  completion  by
selecting  the   socket   for   writing.   After
select(2)  indicates  writability,  use getsock-
opt(2) to read  the  SO_ERROR  option  at  level
SOL_SOCKET  to  determine whether connect() com-
pleted successfully (SO_ERROR is zero) or unsuc-
cessfully  (SO_ERROR  is  one of the usual error
codes listed here, explaining the reason for the
failure).

实现:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>
#include <time.h>
#include <arpa/inet.h>

int main(int argc, char *argv[])
{
 int fd, retval;
 struct sockaddr_in addr;
 struct timeval timeo = {3, 0};
 socklen_t len = sizeof(timeo);
 fd_set set;

 fd = socket(AF_INET, SOCK_STREAM, 0);
 if (argc == 4) timeo.tv_sec = atoi(argv[3]);
 int savefl = fcntl(fd,F_GETFL);
 fcntl(fd, F_SETFL, savefl | O_NONBLOCK);
 addr.sin_family = AF_INET;
 addr.sin_addr.s_addr = inet_addr(argv[1]);
 addr.sin_port = htons(atoi(argv[2]));
 printf("%d/n", time(NULL));
 if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) == 0)
 { 
  close(fd);
  printf("connected ... 1/n");
  return 0;
 }

 if (errno != EINPROGRESS)
 {
  close(fd);
  perror("connect ... 2");
  return -1;
 }

 FD_ZERO(&set);
 FD_SET(fd, &set);
 retval = select(fd + 1, NULL, &set, NULL, &timeo);
 if (retval == -1)
 {
  close(fd);
  perror("select");
  return -1;
 }
 else if(retval == 0)
 {
  close(fd);
  fprintf(stderr, "timeout/n");
  printf("%d/n", time(NULL));
  return 0;
 }

 if(FD_ISSET (fd,&set)) //|| FD_ISSET(SockFd,&wset))
 {
  int error = 0;
  socklen_t len = sizeof (error);
  if(getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0)
  {
   close(fd);
   printf ("getsockopt fail,connected fail/n");   
   return -1;
  }

  if(error == ETIMEDOUT)
  {
   printf ("connected timeout/n");
  }

  if(error == ECONNREFUSED)
  {
   close(fd);
   printf("No one listening on the remote address./n");
   return -1;
  }
 }
 printf ("connected ... 3/n");
 fcntl(fd, F_SETFL, savefl);
 close (fd);

 return 0;
}

原创粉丝点击