//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); 来判断是否发生了错误。