``` /** * write_timeout - 写超时检测函数,不含写操作 * @fd: 文件描述符 * @wait_seconds: 等待超时秒数,如果为0表示不检测超时 * 成功(未超时)返回0,失败返回-1,超时返回-1并且errno = ETIMEDOUT */ int write_timeout(int fd, unsigned int wait_seconds) { int ret = 0; if (wait_seconds > 0) { fd_set write_fdset; struct timeval timeout; FD_ZERO(&write_fdset); FD_SET(fd, &write_fdset); timeout.tv_sec = wait_seconds; timeout.tv_usec = 0; do { ret = select(fd + 1, NULL, &write_fdset, NULL, &timeout); } while (ret < 0 && errno == EINTR); if (ret == 0) { ret = -1; errno = ETIMEDOUT; } else if (ret == 1) ret = 0; } return ret; } ``` ``` /** * connect_timeout - connect * @fd: 套接字 * @addr: 要连接的对方地址 * @wait_seconds: 等待超时秒数,如果为0表示正常模式 * 成功(未超时)返回0,失败返回-1,超时返回-1并且errno = ETIMEDOUT */ static int connect_timeout(int fd, struct sockaddr_in *addr, unsigned int wait_seconds) { int ret; socklen_t addrlen = sizeof(struct sockaddr_in); if (wait_seconds > 0) activate_nonblock(fd); ret = connect(fd, (struct sockaddr*)addr, addrlen); if (ret < 0 && errno == EINPROGRESS) { //printf("11111111111111111111\n"); fd_set connect_fdset; struct timeval timeout; FD_ZERO(&connect_fdset); FD_SET(fd, &connect_fdset); timeout.tv_sec = wait_seconds; timeout.tv_usec = 0; do { // 一但连接建立,则套接字就可写 所以connect_fdset放在了写集合中 ret = select(fd + 1, NULL, &connect_fdset, NULL, &timeout); } while (ret < 0 && errno == EINTR); if (ret == 0) { ret = -1; errno = ETIMEDOUT; } else if (ret < 0) return -1; else if (ret == 1) { //printf("22222222222222222\n"); /* ret返回为1(表示套接字可写),可能有两种情况,一种是连接建立成功,一种是套接字产生错误,*/ /* 此时错误信息不会保存至errno变量中,因此,需要调用getsockopt来获取。 */ int err; socklen_t socklen = sizeof(err); int sockoptret = getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &socklen); if (sockoptret == -1) { return -1; } if (err == 0) { //printf("3333333333333\n"); ret = 0; } else { //printf("4444444444444444:%d\n", err); errno = err; ret = -1; } } } if (wait_seconds > 0) { deactivate_nonblock(fd); } return ret; } ``` ``` /** * read_timeout - 读超时检测函数,不含读操作 * @fd: 文件描述符 * @wait_seconds: 等待超时秒数,如果为0表示不检测超时 * 成功(未超时)返回0,失败返回-1,超时返回-1并且errno = ETIMEDOUT */ int read_timeout(int fd, unsigned int wait_seconds) { int ret = 0; if (wait_seconds > 0) { fd_set read_fdset; struct timeval timeout; FD_ZERO(&read_fdset); FD_SET(fd, &read_fdset); timeout.tv_sec = wait_seconds; timeout.tv_usec = 0; //select返回值三态 //1 若timeout时间到(超时),没有检测到读事件 ret返回=0 //2 若ret返回0 表示有read事件发生,返回事件发生的个数 do { ret = select(fd + 1, &read_fdset, NULL, NULL, &timeout); } while (ret < 0 && errno == EINTR); if (ret == 0) { ret = -1; errno = ETIMEDOUT; } else if (ret == 1) ret = 0; } return ret; } ``` ``` /** * accept_timeout - 带超时的accept * @fd: 套接字 * @addr: 输出参数,返回对方地址 * @wait_seconds: 等待超时秒数,如果为0表示正常模式 * 成功(未超时)返回已连接套接字,超时返回-1并且errno = ETIMEDOUT */ int accept_timeout(int fd, struct sockaddr_in *addr, unsigned int wait_seconds) { int ret; socklen_t addrlen = sizeof(struct sockaddr_in); if (wait_seconds > 0) { fd_set accept_fdset; struct timeval timeout; FD_ZERO(&accept_fdset); FD_SET(fd, &accept_fdset); timeout.tv_sec = wait_seconds; timeout.tv_usec = 0; do { ret = select(fd + 1, &accept_fdset, NULL, NULL, &timeout); } while (ret < 0 && errno == EINTR); if (ret == -1) return -1; else if (ret == 0) { errno = ETIMEDOUT; return -1; } } //一但检测出 有select事件发生,表示对等方完成了三次握手,客户端有新连接建立 //此时再调用accept将不会堵塞 if (addr != NULL) ret = accept(fd, (struct sockaddr*)addr, &addrlen); //返回已连接套接字 else ret = accept(fd, NULL, NULL); if (ret == -1) { ret = errno; Socket_Log(__FILE__, __LINE__, SocketLevel[4], ret, "func accept() err"); return ret; } return ret; } ``` ``` /** * activate_noblock - 设置I/O为非阻塞模式 * @fd: 文件描符符 */ int activate_nonblock(int fd) { int ret = 0; int flags = fcntl(fd, F_GETFL); if (flags == -1) { ret = flags; Socket_Log(__FILE__, __LINE__, SocketLevel[4], ret, "func activate_nonblock() err"); return ret; } flags |= O_NONBLOCK; ret = fcntl(fd, F_SETFL, flags); if (ret == -1) { Socket_Log(__FILE__, __LINE__, SocketLevel[4], ret, "func activate_nonblock() err"); return ret; } return ret; } /** * deactivate_nonblock - 设置I/O为阻塞模式 * @fd: 文件描符符 */ int deactivate_nonblock(int fd) { int ret = 0; int flags = fcntl(fd, F_GETFL); if (flags == -1) { ret = flags; Socket_Log(__FILE__, __LINE__, SocketLevel[4], ret, "func deactivate_nonblock() err"); return ret; } flags &= ~O_NONBLOCK; ret = fcntl(fd, F_SETFL, flags); if (ret == -1) { Socket_Log(__FILE__, __LINE__, SocketLevel[4], ret, "func deactivate_nonblock() err"); return ret; } return ret; } ```
tcp通讯超时处理
1
2
3
4