//read操作加上超时时间。
1 int read_timeout(int fd, void *buf, uint32_t count, int time) 2 { 3 if(time > 0) { 4 fd_set rSet; 5 FD_ZERO(&rSet); 6 FD_SET(fd, &rSet); 7 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 int write_timeout(int fd, void *buf, uint32_t count, int time) 2 { 3 if(time > 0) { 4 fd_set wSet; 5 FD_ZERO(&wSet); 6 FD_SET(fd, &wSet); 7 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 }
accept超时操作
int accept_timeout(int fd, struct sockaddrin *addr, socklen_t *addrlen, int time) { int ret; if(time > 0) { fd_set rSet; FD_ZERO(&rSet); FD_SET(fd, &rSet); struct timeval timeout; timeout.tv_sec = time; timeout.tv_usec = 0; int selectRet; do { selectRet = select(fd + 1, &rSet, NULL, NULL, &timeout); }while(selectRet < 0 && selectRet == EINTR); if(selectRet < 0 ) { return -1; } else if(selectRet == 0) { errno = ETIMEDOUT; return -1; } } if(addr) { ret = accept(fd, (struct sockaddr *)addr, addrlen); } else { ret = accept(fd, NULL, NULL); } return ret; }
检测监听套接字是否可读,当监听套接字可读的时候,就认为连接队列发生了连接。
connect
1 void setNonBlockMode(int fd) 2 { 3 int flags = fcntl(fd, F_GETFL); 4 if(flags < 0) { 5 ERR_EXIT("fcntl"); 6 } 7 flags |= O_NONBLOCK; 8 if(fcntl(fd, F_SETFL, flags) < 0) { 9 ERR_EXIT("fcntl"); 10 } 11 } 12 13 void setBlockMode(int fd) 14 { 15 int flags = fcntl(fd, F_GETFL); 16 if(flags < 0) { 17 ERR_EXIT("fcntl"); 18 } 19 flags &= ~O_NONBLOCK; 20 if(fcntl(fd, F_SETFL, flags) < 0) { 21 ERR_EXIT("fcntl"); 22 } 23 24 } 25 26 int connect_timeout(int sockfd, struct sockaddrin *addr, socklen_t addrlen, int time) 27 { 28 int ret = -1; 29 30 if(time > 0) { 31 setNonBlockMode(sockfd); 32 } 33 ret = connect(sockfd, (struct sockaddr*)addr, addrlen); 34 if(ret < 0 && errno == EINPROGRESS) { 35 fd_set wSet; 36 FD_ZERO(&wSet); 37 FD_SET(sockfd, &wSet); 38 39 struct timeval timeout; 40 timeout.tv_sec = time; 41 timeout.tv_usec = 0; 42 43 int selcetRet; 44 do{ 45 selcetRet = select(sockfd + 1, NULL, &wSet, NULL, &timeout); 46 }while(selcetRet < 0 && errno == EINTR); 47 if(selcetRet < 0) { 48 ret = -1; 49 } else if(selcetRet == 0) { 50 ret = -1; 51 errno = ETIMEDOUT; 52 } else if(selcetRet > 0) { 53 int err; 54 socklen_t socklen = sizeof(err); 55 int sockoptRet = getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &err, &socklen); 56 if(sockoptRet == -1) { 57 ret = -1; 58 } 59 if(err == 0) { 60 ret = 0; 61 } else { 62 errno = err; 63 ret = -1; 64 } 65 } 66 } 67 if(time > 0) { 68 setBlockMode(sockfd); 69 } 70 return ret; 71 }
1.设置fd为非阻塞模式。
2.调用connect操作,如果网络条件很好,比如本机两个socket发生连接,会发生成功返回。
3.正常情况下,connect立即返回-1并设置errno为EINPROGRESS 表示正在连接过程中。
4.使用select检测fd是否可写。 如果检测到可写也有如下两种情况:
1. connect连接成功。
2. 产生了错误,我们就需要用getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &err, &socklen); 来判断是否发生了错误。