TCP解决connect函数的超时问题

在一个TCP套接口被设置为非阻塞之后调用connect,connect会立即返回EINPROGRESS错误,表示连接操作正在进行中,但是仍未完成;同时TCP的三路握手操作继续进行;在这之后,我们可以调用select来检查这个链接是否建立成功;非阻塞connect有三种用途:
1.我们可以在三路握手的同时做一些其它的处理.connect操作要花一个往返时间完成,而且可以是在任何地方,从几个毫秒的局域网到几百毫秒或几秒的广域网.在这段时间内我们可能有一些其他的处理想要执行;

2.由于我们使用select来等待连接的完成,因此我们可以给select设置一个时间限制,从而缩短connect的超时时间.在大多数实现中,connect的超时时间在75秒到几分钟之间.有时候应用程序想要一个更短的超时时间,使用非阻塞connect就是一种方法;

  1. timeval tm;  
  2. fd_set set;  
  3. unsigned long ul = 1;  
  4. ioctlsocket(sock, FIONBIO, &ul); //设置为非阻塞模式  
  5. bool ret = false;  
  6. if (connect(...) == -1)  
  7. {  
  8.     tm.tv_set  = TIME_OUT_TIME;  
  9.     tm.tv_uset = 0;  
  10.     FD_ZERO(&set);  
  11.     FD_SET(sock, &set);  
  12.   
  13.     if (select(sock, NULL, &set, NULL, &tm) > 0)  
  14.     {  
  15.         getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, (socklen_t *)&len);  
  16.         if (error == 0)  
  17.         {  
  18.             ret = true;  
  19.         }  
  20.         else  
  21.         {  
  22.             ret = false;  
  23.         }  
  24.     }  
  25.     else  
  26.     {  
  27.         ret = false;  
  28.     }  
  29. }  
  30. else  
  31. {  
  32.     ret = true;  
  33. }  
  34. ul = 0;  
  35. ioctlsocket(sock, FIONBIO, &ul); //设置为阻塞模式  
  36. if(!ret)   
  37. {  
  38.     close( sockfd );  
  39.     printf(stderr , "Cannot Connect the server!/n");  
  40.     return;  
  41. }  
  42. printf( stderr , "Connected!/n");  

代码思路: 

1.建立socket
 2
.将该socket设置为非阻塞模式
 3
.调用connect()
 4
.使用select()检查该socket描述符是否可写

 5.根据select()返回的结果判断connect()结果
 6
.将socket重设置为阻塞模式

 

所谓阻塞函数,是指其完成指定的任务之前不允许程序调用另一个函数,在Windows下还会阻塞本线程消息的发送。

所谓非阻塞函数,是指操作启动之后,如果可以立即得到结果就返回结果,否则返回表示结果需要等待的错误信息,不等待任务完成函数就返回。

首先,异步函数是非阻塞函数;

其次,获取远地信息的数据库函数是阻塞函数(因此,WinSock提供了其异步版本);

下面对具体函数做解释:

[cpp]   view plain  copy
  1. int select(  
  2.   __in          int nfds,//本参数忽略,仅起到兼容作用  
  3.   __in_out      fd_set* readfds,//指向一组等待可读性检查的套接口,可为NULL  
  4.   __in_out      fd_set* writefds,//指向一组等待可写性检查的套接口,可为NULL  
  5.   __in_out      fd_set* exceptfds,//指向一组等待错误检查的套接口,可为NULL  
  6.   __in          const struct timeval* timeout//select()最多等待时间,对阻塞操作则为NULL  
  7. );  
  8.   
  9.   
  10.    

 

 本函数用于确定一个或多个套接口的状态。对每一个套接口,调用者可查询它的可读性、可写性及错误状态信息。用fd_set结构来表示一组等待检查的套接口

 readfds参数标识等待可读性检查的套接口。如果该套接口正处于监听listen()状态,则若有连接请求到达,该套接口便被标识为可读,这样一个accept()调用保证可以无阻塞完成。对其他套接口而言,可读性意味着有排队数据供读取。或者对于SOCK_STREAM类型套接口来说,相对于该套接口的虚套接口已关闭,于是recv()或recvfrom()操作均能无阻塞完成

writefds参数标识等待可写性检查的套接口。如果一个套接口正在connect()连接(非阻塞),可写性意味着连接顺利建立。如果套接口并未处于connect()调用中,可写性意味着send()和sendto()调用将无阻塞完成。〔但并未指出这个保证在多长时间内有效,特别是在多线程环境中〕。

exceptfds参数标识等待带外数据存在性或意味错误条件检查的套接口。请注意如果设置了SO_OOBINLINE选项为假FALSE,则只能用这种方法来检查带外数据的存在与否。对于SO_STREAM类型套接口,远端造成的连接中止和KEEPALIVE错误都将被作为意味出错。如果套接口正在进行连接connect()(非阻塞方式),则连接试图的失败将会表现在exceptfds参数中。

返回值:
   select()调用返回处于就绪状态并且已经包含在fd_set结构中的描述字总数;如果超时则返回0;否则的话,返回SOCKET_ERROR错误,应用程序可通过WSAGetLastError()获取相应错误代码。


  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
在 CSDN 开发的 C 知道 中,您可以使用一些套接字选项来设置 TCP 连接的超时时间。一种常用的方法是使用 `connect()` 函数之前,使用 `setsockopt()` 函数设置 `SO_RCVTIMEO` 或 `SO_SNDTIMEO` 选项。 以下是一个示例代码片段,展示了如何设置连接超时时间为 5 秒: ```c #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> int main() { int sockfd; struct sockaddr_in server_addr; int connect_timeout = 5; // 超时时间为 5 秒 // 创建套接字 sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd == -1) { perror("socket"); exit(1); } // 设置连接超时选项 struct timeval timeout; timeout.tv_sec = connect_timeout; timeout.tv_usec = 0; if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) == -1) { perror("setsockopt"); exit(1); } if (setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)) == -1) { perror("setsockopt"); exit(1); } // 设置服务器地址 server_addr.sin_family = AF_INET; server_addr.sin_port = htons(8080); // 设置服务器端口号 server_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); // 设置服务器 IP 地址 // 连接服务器 if (connect(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1) { perror("connect"); exit(1); } // 连接成功,进行后续操作 // 关闭套接字 close(sockfd); return 0; } ``` 在上述示例中,我们使用了 `setsockopt()` 函数来设置 `SO_RCVTIMEO` 和 `SO_SNDTIMEO` 选项,将超时时间设置为 5 秒。这样,在调用 `connect()` 函数时,如果连接超时或者连接过程中发生错误,会返回相应的错误码。 请注意,以上代码仅用于演示如何设置连接超时时间,实际应用中可能需要根据具体情况进行适当修改。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值