/** * connect_timeout - connect * @fd: 套接字 * @addr: 要连接的对方地址 * @wait_seconds: 等待超时秒数,如果为0表示正常模式 * 成功(未超时)返回0,失败返回-1,超时返回-1并且errno = ETIMEDOUT */ 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) { 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 { /* 一量连接建立,套接字就可写 */ 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) { /* 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) { ret = 0; } else { errno = err; ret = -1; } } } if (wait_seconds > 0) { deactivate_nonblock(fd); } return ret; }
int connect_timeout(int sockfd,const struct sockaddr *addr, socklen_t addrlen,int tval) { int ret = 0; if(tval > 0) { //这里首先进行connect操作,然后是 //定时看连接是否超时,如果不超时就可以写了 //所以不能阻塞到连接成功, //而应该通过select来定时判断是否连接成功 activate_nonblock(sockfd); } ret = connect(sockfd,(struct sockaddr *)addr,addrlen); if(ret < 0 && EINPROGRESS == errno) { fd_set connect_fdset; struct timeval timeout; timeout.tv_sec = tval; timeout.tv_usec = 0; FD_ZERO(&connect_fdset); FD_SET(sockfd,&connect_fdset); do { ret = select(sockfd + 1,NULL,&connect_fdset,NULL,&timeout); } while(ret < 0 && EINTR == errno); if(0 == ret) { //timeout errno = ETIMEDOUT; ret = -1; } else if(ret < 0) { return ret; } else { //这里返回有两种情况,要么是连接成功,要么连接失败, //但是连接失败不会在select中以错误的方式返回 //所以需要再次使用getsockopt来进行近一步的判断 int err; socklen_t socklen = sizeof(err); int sockoptret = getsockopt(sockfd,SOL_SOCKET,SO_ERROR,&err,&socklen); if(-1 == sockoptret) { return sockoptret; } if(0 == err) { ret = 0; } else { errno = err; ret = -1; } } } //要恢复阻塞的状态 if(tval > 0) { deactivate_nonblock(sockfd); } return ret; }
int connect_timeout(int fd, struct sockaddr *addr, unsigned int wait_seconds) { int ret = 0; socklen_t addrlen = sizeof(struct sockaddr_in); if(wait_seconds > 0) activate_nonblock(fd); ret = connect(fd, (struct sockaddr *)addr, addrlen); if(ret == -1 && errno == EINPROGRESS) { fd_set connect_fdset; FD_ZERO(&connect_fdset); FD_SET(fd, &connect_fdset); struct timeval timeout; timeout.tv_sec = wait_seconds; timeout.tv_usec = 0; do{ ret = select(fd+1, NULL, &connect_fdset, NULL, &timeout); }while(ret == -1 && errno == EINTR); if(ret == 0){ ret = -1; errno = ETIMEDOUT; }else if(ret < 0){ ret = -1; }else if(ret == 1){ int err; socklen_t socklen = sizeof(err); int sockoptret = getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &socklen); if(sockoptret == -1){ return -1; }else if(err == 0){ ret = 0; }else{ errno = err; ret = -1; } } } if(wait_seconds > 0){ deactivate_nonblock(fd); } return ret; }
/* * 函数名:connect_timeout * 描述:客服端接受数据 * 参数: * * 返回: * */ int connect_timeout(int fd, struct sockaddr_in *addr, unsigned int wait_seconds) { int ret; //获取socket结构体的大小。 socklen_t addrlen = sizeof(struct sockaddr_in); //如果传入的等待时间大于0就取消socket的阻塞状态,0则不执行。 if (wait_seconds > 0) activate_nonblock(fd); //链接 /* * int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen); * * */ ret = connect(fd, (struct sockaddr*) addr, addrlen); //EINPROGRESS 正在处理 if (ret < 0 && errno == EINPROGRESS) { /* * void FD_CLR(int fd, fd_set *set); * int FD_ISSET(int fd, fd_set *set); * void FD_SET(int fd, fd_set *set); * void FD_ZERO(fd_set *set); * */ //设置监听集合 fd_set connect_fdset; struct timeval timeout; //初始化集合 FD_ZERO(&connect_fdset); //把fd 文件描述符的socket加入监听集合 FD_SET(fd, &connect_fdset); /* * struct timeval { * long tv_sec; // seconds 秒 * long tv_usec; // microseconds 微妙 * }; * */ 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; /* * #define ETIMEDOUT 110 // Connection timed out * Tcp是面向连接的。在程序中表现为,当tcp检测到对端socket不再可 * 用时(不能发出探测包,或探测包没有收到ACK的响应包),select会 * 返回socket可读,并且在recv时返回-1,同时置上errno为ETIMEDOUT。 * */ 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); //获取socket的状态 int sockoptret = getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &socklen); if (sockoptret == -1) { return -1; } if (err == 0) { ret = 0; } else { errno = err; ret = -1; } } } if (wait_seconds > 0) { deactivate_nonblock(fd); } return ret; }
/** * connect_timeout - connect * @fd: 套接字 * @addr: 要连接的对方地址 * @wait_seconds: 等待超时秒数,如果为0表示正常模式 * 成功(未超时)返回0,失败返回-1,超时返回-1并且errno = ETIMEDOUT */ 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) { /* 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 { ret = select(fd + 1, NULL, &connect_fdset, NULL, &timeout); } while (ret < 0 && errno == EINTR); */ int epfd; epfd = epoll_create1(0); struct epoll_event evn; struct epoll_event *events = NULL; evn.data.fd = fd; evn.events = EPOLLOUT | EPOLLET; epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &evn); do{ ret = epoll_wait(epfd, events, MAXEVENTS, wait_seconds); }while(ret < 0 && errno == EINTR); if (ret == 0) { ret = -1; errno = ETIMEDOUT; } else if (ret < 0) return -1; else if (ret == 1) { /* 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) { ret = 0; } else { errno = err; ret = -1; } } } if (wait_seconds > 0) { deactivate_nonblock(fd); } return ret; }