如何解决Connect超时导致的阻塞问题
来源:互联网 发布:java接口文档怎么写 编辑:程序博客网 时间:2024/04/26 03:49
这几天发现一个现象,客户端正常连接服务器connect显然不会出现问题。
在异常情况下,如果是服务器出现异常,connect能够立即返回失败;但是当客户端出现异常的情况下,分为两种情况:
一种是不插网线,客户端没有获得ip地址,在这种情况下,connect也可以立即返回错误;
二是但是当客户端插上网线,但是连接网络失败,也就是说能够获取到ip地址,但是和服务器是ping不通的。这种情况下connect就可能会发生阻塞,因为按照《UNIX 网络编程》中讲解,connect的在进行三次握手,如果失败情况,需要等待75s的超市时间的。
我们主要讨论第二种情况如何解决,可以让connect快速返回结果,不至于阻塞等待超长的时间。
如下是我的代码
/******************************* Time out for connect()******************************/#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <netinet/in.h>#include <sys/socket.h>#include <sys/types.h>#include <sys/time.h>#include <arpa/inet.h>#include <fcntl.h>#include <string.h>#include <errno.h>#define TIME_OUT_TIME 20 //connect超时时间20秒bool setBlockOpt(int m_fd,bool blocked){#ifndef WIN32int flags;flags = fcntl(m_fd, F_GETFL, 0);if(flags < 0){return false;}if(blocked){printf("Set BLOCK !!!\n");flags &= ~O_NONBLOCK;}else{printf("Set NONBLOCK !!!\n");flags |= O_NONBLOCK;}if(fcntl(m_fd, F_SETFL, flags) < 0){return false;}#elseu_long ulValue;if(blocked){ulValue = 1;}else{ulValue = 0;}int n = ioctlsocket(m_fd, FIONBIO, &ulValue);if (n != 0){return false;}#endifreturn true;}int connectWithTimeout(int m_fd,int timeout){int selectFlag = -1;int error=-1, len;len = sizeof(int);bool ret = false;int connectFlag = -1;const char* m_ip = "115.239.210.27";int m_port = 80;if("" == m_ip || 0 > m_port){return -1;}if(m_fd < 0 && "" != m_ip && m_port >=0){m_fd = socket(AF_INET, SOCK_STREAM, 0);if(m_fd < 0){return -1;}}if(m_fd < 0){return -1;}struct sockaddr_in servAddr;memset(&servAddr, 0, sizeof(servAddr));servAddr.sin_family = AF_INET;servAddr.sin_port = htons((unsigned short)m_port);servAddr.sin_addr.s_addr = inet_addr(m_ip);setBlockOpt(m_fd,false);//设置为非阻塞模式if( (connectFlag= connect(m_fd, (struct sockaddr *) &servAddr, sizeof(servAddr)) < 0)){if(errno != EINPROGRESS){goto done;}}else{ret = true;goto done;}timeval tm;tm.tv_sec = timeout/1000;tm.tv_usec = timeout%1000;fd_set rest, west;FD_ZERO(&rest);FD_ZERO(&west);FD_SET(m_fd, &rest);FD_SET(m_fd, &west);if( (selectFlag = select(m_fd+1, &rest, &west, NULL, &tm)) > 0){//如果套接口及可写也可读,需要进一步判断if(FD_ISSET(m_fd, &rest) && FD_ISSET(m_fd, &west)) {if(getsockopt(m_fd, SOL_SOCKET, SO_ERROR, &error, (socklen_t *)&len) < 0){printf("getsockopt error!!!\n");}else{if(error == 0){ret = true;}else {printf("connect getsockopt error!!! %d\n",error);}}}//如果套接口可写不可读,则链接完成else if(FD_ISSET(m_fd, &west) && !FD_ISSET(m_fd, &rest)) { ret = true;}}else if(selectFlag == 0){printf("connect select timeout!!!\n");}else {printf("connect select error!!!\n");}done:setBlockOpt(m_fd,true);// 设置为阻塞模式if(!ret){return -1;}return 0;}int main(int argc,char* argv[]){if(argc <= 1){printf("input error!!!\n");exit(1);}int sockfd = socket(AF_INET, SOCK_STREAM, 0);if(sockfd < 0) {exit(1);}if(connectWithTimeout(sockfd,atoi(argv[1])) == 0){printf("connect sucess!!!\n");}else{printf("connect filed!!!\n");}close(sockfd);return 0;}
原理很简单,就是先把套接字设置为非阻塞,因为在非阻塞情况下,connect的结果是立即返回的,然后我们再使用select或者poll等机制来检测套接字一定的时间,如果在超时时间内不可写,则认为connect失败,然后需要把套接字重新设置为阻塞,当然如果你不需要在阻塞模式下工作,可以不用设置。
如上,我们就可以对connect的超时进行可控。
1 0
- 如何解决Connect超时导致的阻塞问题
- 非阻塞connect导致的问题
- TCP解决connect函数的超时问题
- Windows上如何玩非阻塞的connect?---让程序员自定义connect函数的超时时间
- windows下如何解决PHP调用的外部程序超时阻塞问题
- 设置socket的Connect超时 同步 阻塞
- 非阻塞模式的设置、设置socket为非阻塞模式 解决connect阻塞问题
- 解决curl超时导致应用崩溃的问题
- 解决curl超时导致应用崩溃的问题
- 使用非阻塞socket来控制connect的超时
- 如何设置socket的Connect超时(linux)?
- 如何设置socket的Connect超时(linux)
- 如何设置socket的Connect超时(linux)
- 如何设置socket的Connect超时(linux)
- 如何设置socket的Connect超时(linux)
- 如何设置socket的Connect超时(linux)
- 如何设置socket的Connect超时
- 如何设置socket的connect() recvfrom() 超时
- 【Deep Learning】Review:Faster R-CNN- TowardsReal-Time Object Detection with Region Proposal Networks
- linux 驱动之 dts
- Hdu 3342 Legal or Not
- ffmpeg解码流程
- 第 22 章 声音和音乐
- 如何解决Connect超时导致的阻塞问题
- 2012年第三届蓝桥杯C/C++程序设计本科B组省赛 密码发生器(编程大题)
- ThinkPHP将Session保存到mysql
- 理解LDAP与LDAP注入
- matlab使用BP神经网络训练如何不出现训练窗口
- 晚期(运行期)优化
- Qt/Qte/Qtopia三者的区别
- 如何解决PHP查询大量数据内存耗尽的问题
- CocoaPods使用