原文地址:http://blog.csdn.net/codeheng/article/details/44625495

在使用TCP的connect连接服务器时,在默认情况下系统使用的是阻塞式socket,如果服务器当前不可用,则connect会等待知道超时时间到达,而这个超时时间是系统内核规定的,并不能使用setSocketOpt来设置,这个函数只能设置send和recv的超时,为了能够随意控制connect的超时时间,可以使用select。大致的过程就是先将socket设置成非阻塞,使用select去轮询套接口,再根据套接口去判断连接状态。

int connectServer(int sock_fd,unsigned int port,char* ip)
{struct sockaddr_in servaddr;bzero(&servaddr, sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_port = htons(port);inet_aton(ip, &servaddr.sin_addr );fcntl(sock_fd,F_SETFL,fcntl(sock_fd,F_GETFL,0)|O_NONBLOCK);int connected = connect(sock_fd, (struct sockaddr*)&servaddr, sizeof(struct sockaddr_in));int ret = -1;if (connected != 0 ){if(errno != EINPROGRESS)printf("connect error :%s\n",strerror(errno));else{struct timeval tm = {2, 0};fd_set wset,rset;FD_ZERO(&wset);FD_ZERO(&rset);FD_SET(sock_fd,&wset);FD_SET(sock_fd,&rset);long t1 = time(NULL);int res = select(sock_fd+1,&rset,&wset,NULL,&tm);long t2 = time(NULL);printf("interval time: %ld\n", t2 - t1);if(res < 0){printf("network error in connect\n");}else if(res == 0){printf("connect time out\n");}else if (1 == res){if(FD_ISSET(sock_fd,&wset)){printf("connect succeed.\n");fcntl(sock_fd,F_SETFL,fcntl(sock_fd,F_GETFL,0) & ~O_NONBLOCK);ret = 0;}else{printf("other error when select:%s\n",strerror(errno));}}}}return ret;
}

程序先把socket设置成非阻塞,connect在非阻塞模式下会立刻返回,如果没有其他错误,返回值等于0。当connect不能立刻建立连接时,会返回一个EINPROGRESS,表示连接正在建立的过程中,这时我们可以使用select去轮询套接口,而select的轮询超时时间可以根据自己的需要去设置,最主要的是轮询的集合一定要是读和写的集合,即select的第二和第三个参数要赋值,待select返回就可以去判断返回值来确定connect的进程状态了。如果返回值小于0,说明connect的进程出现了错误,如果是等于0则说明connect超时,如果等于1,并且套接口此时的状态是可写,则说明了connect已经成功建立(关于这点大概是因为服务器接收了连接后,不会立刻想socket写数据,这是客户端就只能轮询到可写的socket,我觉得如果服务器接受连接并立刻写数据,在客户端就可能是返回2,这时学要同时判断socket的可读和可写了);其他情况的话就算是其他错误吧,至此,我们只需要设置select的超时值就可以随心所欲地实现自己想要的connect连接超时了。

最后,别忘了把套接口设置会阻塞状态,毕竟阻塞状态加线程方便控制。

vc++驿站

http://www.cctry.com/thread-25777-1-1.html
1.首先将标志位设为Non-blocking模式,准备在非阻塞模式下调用connect函数
2.调用connect,正常情况下,因为TCP三次握手需要一些时间;而非阻塞调用只要不能立即完成就会返回错误,所以这里会返回EINPROGRESS,表示在建立连接但还没有完成。
3.在读套接口描述符集(fd_set rset)和写套接口描述符集(fd_set wset)中将当前套接口置位(用FD_ZERO()、FD_SET()宏),并设置好超时时间(struct timeval *timeout)
4.调用select( socket, &rset, &wset, NULL, timeout ) 返回0表示connect超时如果你设置的超时时间大于75秒就没有必要这样做了,因为内核中对connect有超时限制就是75秒。

网络编程中socket的分量我想大家都很清楚了,socket也就是套接口,在套接口编程中,提到超时的概念,我们一下子就能想到3个:发送超时,接收超时,以及select超时(注: select函数并不是只用于套接口的,但是套接口编程中用的比较多),在connect到目标主机的时候,这个超时是不由我们来设置的。不过正常情况下这个超时都很长,并且connect又是一个阻塞方法,一个主机不能连接,等着connect返回还能忍受,你的程序要是要试图连接多个主机,恐怕遇到多个不能连接的主机的时候,会塞得你受不了的。我也废话少说,先说说我的方法,如果你觉得你已掌握这种方法,你就不用再看下去了,如果你还不了解,我愿意与你分享。本文是已在Linux下的程序为例子,不过拿到Windows中方法也是一样,无非是换几个函数名字罢了。
Linux中要给connect设置超时,应该是有两种方法的。一种是该系统的一些参数,这个方法我不讲,因为我讲不清楚:P,它也不是编程实现的。另外一种方法就是变相的实现connect的超时,我要讲的就是这个方法,原理上是这样的:
1.建立socket
2.将该socket设置为非阻塞模式
3.调用connect()
4.使用select()检查该socket描述符是否可写(注意,是可写)
5.根据select()返回的结果判断connect()结果
6.将socket设置为阻塞模式(如果你的程序不需要用阻塞模式的,这步就省了,不过一般情况下都是用阻塞模式的,这样也容易管理)
如果你对网络编程很熟悉的话,其实我一说出这个过程你就知道怎么写你的程序了,下面给出我写的一段程序,仅供参考。

/******************************
* Time out for connect()
* Write by Kerl W
******************************/
#include
#include
#define TIME_OUT_TIME 20 //connect超时时间20秒
int main(int argc , char **argv)
{
………………
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd < 0) exit(1);
struct sockaddr_in serv_addr;
………//以服务器地址填充结构serv_addr
int error=-1, len;
len = sizeof(int);
timeval tm;
fd_set set;
unsigned long ul = 1;
ioctl(sockfd, FIONBIO, &ul); //设置为非阻塞模式
bool ret = false;
if( connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == -1)
{
tm.tv_set = TIME_OUT_TIME;
tm.tv_uset = 0;
FD_ZERO(&set);
FD_SET(sockfd, &set);
if( select(sockfd+1, NULL, &set, NULL, &tm) > 0)
{
getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, (socklen_t *)&len);
if(error == 0) ret = true;
else ret = false;
} else ret = false;
}
else ret = true;
ul = 0;
ioctl(sockfd, FIONBIO, &ul); //设置为阻塞模式
if(!ret)
{
close( sockfd );
fprintf(stderr , "Cannot Connect the server!\n");
return;
}
fprintf( stderr , "Connected!\n");
//下面还可以进行发包收包操作
……………
}

以上代码片段,仅供参考,也是为初学者提供一些提示,主要用到的几个函数,select, ioctl, getsockopt都可以找到相关资料,具体用法我这里就不赘述了,你只需要在linux中轻轻的敲一个man <函数名>就能够看到它的用法。
此外我需要说明的几点是,虽然我们用ioctl把套接口设置为非阻塞模式,不过select本身是阻塞的,阻塞的时间就是其超时的时间由调用select 的时候的最后一个参数timeval类型的变量指针指向的timeval结构变量来决定的,timeval结构由一个表示秒数的和一个表示微秒数(long类型)的成员组成,一般我们设置了秒数就行了,把微妙数设为0(注:1秒等于100万微秒)。而select函数另一个值得一提的参数就是上面我们用到的fd_set类型的变量指针。调用之前,这个变量里面存了要用select来检查的描述符,调用之后,针对上面的程序这里面是可写的描述符,我们可以用宏FD_ISSET来检查某个描述符是否在其中。由于我这里只有一个套接口描述符,我就没有使用FD_ISSET宏来检查调用select之后这个sockfd是否在set里面,其实是需要加上这个判断的。不过我用了getsockopt来检查,这样才可以判断出这个套接口是否是真的连接上了,因为我们只是变相的用select来检查它是否连接上了,实际上select检查的是它是否可写,而对于可写,是针对以下三种条件任一条件满足时都表示可写的:
1)套接口发送缓冲区中的可用控件字节数大于等于套接口发送缓冲区低潮限度的当前值,且或者i)套接口已连接,或者ii)套接口不要求连接(UDP方式的)
2)连接的写这一半关闭。
3)有一个套接口错误待处理。
这样,我们就需要用getsockopt函数来获取套接口目前的一些信息来判断是否真的是连接上了,没有连接上的时候还能给出发生了什么错误,当然我程序中并没有标出那么多状态,只是简单的表示可连接/不可连接。
下面我来谈谈对这个程序测试的结果。我针对3种情形做了测试:
1. 目标机器网络正常的情况
可以连接到目标主机,并能成功以阻塞方式进行发包收包作业。
2. 目标机器网络断开的情况
在等待设置的超时时间(上面的程序中为20秒)后,显示目标主机不能连接。
3. 程序运行前断开目标机器网络,超时时间内,恢复目标机器的网络
在恢复目标主机网络连接之前,程序一只等待,恢复目标主机后,程序显示连接目标主机成功,并能成功以阻塞方式进行发包收包作业。
以上各种情况的测试结果表明,这种设置connect超时的方法是完全可行的。我自己是把这种设置了超时的connect封装到了自己的类库,用在一套监控系统中,到目前为止,运行还算正常。这种编程实现的connect超时比起修改系统参数的那种方法的有点就在于它只用于你的程序之中而不影响系统。

teamtalk 的连接超时
2. socket函数connect()连接等待时长设定
传统的做法是将socket设置为非阻塞的,调用完connect函数之后,调用select函数检测socket是否可写,在select函数里面设置超时时间。代码如下:
红色箭头的地方调用connect函数连接服务器,然后绿色的箭头等待一个事件有信号(内部使用WaitForSingleObject函数),那事件什么时候有信号呢?
网络线程检测第一次到socket可写时,调用onConnectDone函数:
实际做的事情还是和上面介绍的差不多。其实对于登录流程做成同步的,也是和这个类似,上文中我们介绍过。我早些年刚做windows网络通信方面的项目时,开始总是找不到好的处理等待登录请求应答的方法。这里是一种很不错的设置超时等待的方法。

connect 连接超时相关推荐

  1. socket connec连接超时处理

    最近把win32下的网关服务转到linux平台时遇到connect连接超时问题,经过多方收集资料简单整理下方便以后查找 linux或者win32控制台程序中connect函数默认是阻塞的,成功则返回0 ...

  2. connect设置超时的方法

    在使用TCP的connect连接服务器时,在默认情况下系统使用的是阻塞式socket,如果服务器当前不可用,则connect会等待知道超时时间到达,而这个超时时间是系统内核规定的,并不能使用setSo ...

  3. TcpClient.Connect函数连接超时的问题(转载)

    TcpClient.Connect函数连接超时的问题 问题原述: http://topic.csdn.net/t/20060616/15/4825920.html 调用TcpClient.Connec ...

  4. Failed connect to github-production-release-asset-2e65be.s3.amazonaws.com:443; 连接超时

    安装docker-machine的时候, 提示下载错误, 解决方式如下: 1. 错误提示 [root@localhost logs]# curl -L https://github.com/docke ...

  5. 【Redis连接超时】io.lettuce.core.RedisConnectionException: Unable to connect to 192.168.x.x:7000

    「扫码关注我,面试.各种技术(mysql.zookeeper.微服务.redis.jvm)持续更新中-」 今天临近下班了,线上开始频繁报警,各种Redis连接超时,顿时慌的一批,因为最近在优化系统高频 ...

  6. dbeaver的连接超时(Connection timed out: connect)

    项目场景: hiveserver2启动了, 虚拟机 里能启动beeline,并且能连接hive2, 但是就是连接不了win上的dbeaver 问题描述: Could not open client t ...

  7. Failed to connect to github.com port 443 连接超时

    Failed to connect to github.com port 443: 连接超时 在安装fabric环境时遇到了这个问题,解决办法如下: 首先第一次出现了port 80的问题,这时sudo ...

  8. jmeter serveragent连接超时ERROR.java.net.ConnectException.Connection.timed.out.connect解决方法

    前言 jmeter服务器监控的配置我们就不讲了,直接讲讲怎么解决这个连接超时的方法 serveragent 启动 将serveragent解压后,输入./startAgent.sh进行启动,这种启动方 ...

  9. mysql connect 超时_MySQL修改connect_timeout(连接超时)全局变量

    Java程序员儿反应服务器上的MySQL连上去之后,总是过一会儿就断开连接了,工作效率低,跟松哥提需求,增加连接时间,减少断开次数,和刷新页面的等待时间.我自己本地用telnet测试,读秒试了下,果然 ...

最新文章

  1. 纤维追踪成像理论+核磁共振影像数据处理
  2. arcgis python 二次开发_我在部署ArcGIS API for Python时踩到的坑
  3. mysql创建表的时候显式申明字符集
  4. linux KVM win虚拟机磁盘扩容(qcow2)
  5. React之回调ref中回调执行次数的问题
  6. jQuery中iframe的操作
  7. spring boot 与配置
  8. 夏普Sharp MX-M2658N 一体机驱动
  9. word里画的流程图怎么全选_怎么用word画流程图
  10. APP推广技巧:APP营销推广的八种渠道你一定要了解!
  11. 十大歌手Python
  12. 新人运营从0到1怎么做公众号?3000字干货看明白逻辑
  13. 【Spark NLP】第 8 章:使用 Keras 进行序列建模
  14. SCI回复审稿意见的模板
  15. Arbitrary Shape Scene Text Detection with Adaptive Text Region Representation ----论文翻译
  16. 高斯消元法与LU分解
  17. JS 函数中的 arguments 类数组对象
  18. sqlite的下载安装和配置使用(非常详细)
  19. Java 多线程 线程同步
  20. DSP6455开发: dsp.lib库使用总结

热门文章

  1. 手机数据恢复的经历和过程
  2. CDN降价之后又一大招 阿里云PCDN正式开放申请
  3. php各种编码集详解和以及在什么情况下进行使用
  4. python编写一个接口,链接mysql数据库查询数据
  5. LeetCode 1646. 获取生成数组中的最大值 Python
  6. android相关学习网站
  7. Cipher Code
  8. Object.assign与vue $set
  9. 多模态(Fusion)融合的几种骚操作
  10. java 如何实现一个字符串的反转