Chinaunix首页 | 论坛 | 博客
  • 博客访问: 129802
  • 博文数量: 43
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 175
  • 用 户 组: 普通用户
  • 注册时间: 2015-04-10 12:33
文章存档

2016年(9)

2015年(34)

我的朋友

分类: LINUX

2016-01-05 11:02:13

read,write,accept,connect 超时封装 - superPerfect


  1. //read操作加上超时时间。
  2. int read_timeout(int fd, void *buf, uint32_t count, int time)
  3. {
  4.     if(time > 0) {
  5.         fd_set rSet;
  6.         FD_ZERO(&rSet);
  7.         FD_SET(fd, &rSet);

  8.         struct timeval timeout;
  9.         memset(&timeout, 0, sizeof(timeout));
  10.         timeout.tv_sec = time;
  11.         timeout.tv_usec = 0;
  12.         
  13.         int ret;
  14.         while(1) {
  15.             ret = select(fd+1, &rSet, NULL, NULL, &timeout);
  16.             if(ret < 0) {
  17.                 if(errno == EINTR) continue;
  18.                 ERR_EXIT("select");
  19.             } else if(ret == 0) {
  20.                 errno = ETIMEDOUT;
  21.                 return -1;
  22.             } else {
  23.                 break;
  24.             }
  25.         }
  26.     }
  27.     int readNum;
  28.     readNum = read(fd, buf, count);
  29.     return readNum;
  30. }

点击(此处)折叠或打开

  1. //write超时

  2. int write_timeout(int fd, void *buf, uint32_t count, int time)
  3. {
  4.     if(time > 0) {
  5.         fd_set wSet;
  6.         FD_ZERO(&wSet);
  7.         FD_SET(fd, &wSet);

  8.         struct timeval timeout;
  9.         memset(&timeout, 0, sizeof(timeout));
  10.         timeout.tv_sec = time;
  11.         timeout.tv_usec = 0;
  12.         
  13.         int ret;
  14.         while(1) {
  15.             ret = select(fd+1, NULL, &wSet, NULL, &timeout);
  16.             if(ret < 0) {
  17.                 if(errno == EINTR) continue;
  18.                 ERR_EXIT("select");
  19.             } else if(ret == 0) {
  20.                 errno = ETIMEDOUT;
  21.                 return -1;
  22.             } else {
  23.                 break;
  24.             }
  25.         }
  26.     }
  27.     int writeNum;
  28.     writeNum = write(fd, buf, count);
  29.     return writeNum;
  30. }

点击(此处)折叠或打开

  1. //accept超时操作

  2. int accept_timeout(int fd, struct sockaddrin *addr, socklen_t *addrlen, int time)
  3. {
  4.   int ret;
  5.   if(time > 0) {
  6.     fd_set rSet;
  7.     FD_ZERO(&rSet);
  8.     FD_SET(fd, &rSet);

  9.     struct timeval timeout;
  10.     timeout.tv_sec = time;
  11.     timeout.tv_usec = 0;

  12.     int selectRet;
  13.     do {
  14.       selectRet = select(fd + 1, &rSet, NULL, NULL, &timeout);
  15.     }while(selectRet < 0 && selectRet == EINTR);
  16.     if(selectRet < 0 ) {
  17.       return -1;
  18.     } else if(selectRet == 0) {
  19.       errno = ETIMEDOUT;
  20.       return -1;
  21.     }    
  22.   }
  23.   if(addr) {
  24.     ret = accept(fd, (struct sockaddr *)addr, addrlen);
  25.   } else {
  26.     ret = accept(fd, NULL, NULL);
  27.   }
  28.   return ret;
  29. }

点击(此处)折叠或打开

  1. //检测监听套接字是否可读,当监听套接字可读的时候,就认为连接队列发生了连接。

  2. //connect

  3. void setNonBlockMode(int fd)
  4. {
  5.     int flags = fcntl(fd, F_GETFL);
  6.     if(flags < 0) {
  7.         ERR_EXIT("fcntl");
  8.     }
  9.     flags |= O_NONBLOCK;
  10.     if(fcntl(fd, F_SETFL, flags) < 0) {
  11.         ERR_EXIT("fcntl");
  12.     }
  13. }

  14. void setBlockMode(int fd)
  15. {
  16.     int flags = fcntl(fd, F_GETFL);
  17.     if(flags < 0) {
  18.         ERR_EXIT("fcntl");
  19.     }
  20.     flags &= ~O_NONBLOCK;
  21.     if(fcntl(fd, F_SETFL, flags) < 0) {
  22.         ERR_EXIT("fcntl");
  23.     }

  24. }

  25. int connect_timeout(int sockfd, struct sockaddrin *addr, socklen_t addrlen, int time)
  26. {
  27.     int ret = -1;

  28.     if(time > 0) {
  29.         setNonBlockMode(sockfd);
  30.     }
  31.     ret = connect(sockfd, (struct sockaddr*)addr, addrlen);
  32.     if(ret < 0 && errno == EINPROGRESS) {
  33.         fd_set wSet;
  34.         FD_ZERO(&wSet);
  35.         FD_SET(sockfd, &wSet);
  36.         
  37.         struct timeval timeout;
  38.         timeout.tv_sec = time;
  39.         timeout.tv_usec = 0;
  40.         
  41.         int selcetRet;
  42.         do{
  43.             selcetRet = select(sockfd + 1, NULL, &wSet, NULL, &timeout);
  44.         }while(selcetRet < 0 && errno == EINTR);
  45.         if(selcetRet < 0) {
  46.             ret = -1;
  47.         } else if(selcetRet == 0) {
  48.             ret = -1;
  49.             errno = ETIMEDOUT;
  50.         } else if(selcetRet > 0) {
  51.             int err;
  52.             socklen_t socklen = sizeof(err);
  53.             int sockoptRet = getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &err, &socklen);
  54.             if(sockoptRet == -1) {
  55.                 ret = -1;
  56.             }
  57.             if(err == 0) {
  58.                 ret = 0;
  59.             } else {
  60.                 errno = err;
  61.                 ret = -1;
  62.             }
  63.         }
  64.     }
  65.     if(time > 0) {
  66.         setBlockMode(sockfd);
  67.     }
  68.     return ret;
  69. }

  1.设置fd为非阻塞模式。


2.调用connect操作,如果网络条件很好,比如本机两个socket发生连接,会发生成功返回。

3.正常情况下,connect立即返回-1并设置errno为EINPROGRESS 表示正在连接过程中。

4.使用select检测fd是否可写。 如果检测到可写也有如下两种情况:

1. connect连接成功。

2. 产生了错误,我们就需要用getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &err, &socklen); 来判断是否发生了错误。

阅读(1504) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~