在LINUX系统中,系统默认TCP建立连接超时时间为127秒。但是对于应用程序来说,这个超时时间太长了,不利于一些业务的处理。比如说我的应用想通过建立TCP连接来判断服务端程序是否在运行,或者网络是否通达,这时我不可能等127秒。那么应用程序如何实现TCP连接超时呢?
首先我们来看connect函数的帮助说明:
man connect
EINPROGRESS The socket is non-blocking and the connection cannot be completed immediately. It is possible to select(2) or poll(2) for completion by selecting the socket for writing. After select(2) indicates writability, use getsockopt(2) to read the SO_ERROR option at level SOL_SOCKET to determine whether connect() completed successfully (SO_ERROR is zero) or unsuccessfully (SO_ERROR is one of the usual error codes listed here, explaining the reason for the failure).
解释如下:
首先设置socket描述符为非阻塞模式,然后调用connect建立连接,此时连接操作不会立即完成,会返回错误码EINPROGRESS。然后使用select或者epoll来监测socket的写事件,如果超时时间内没有写事件到达,说明连接超时。如果有写事件时,需要获取socket错误码,错误为0时表示连接成功,错误码不为0时表示连接失败。
下面我们按照帮助说明编写一个简单的客户端demo程序来实现连接超时,供大家参考:
#include#include#include#include#include#includeint main(int argc,char *argv[]){//设为非阻塞int sockfd = socket(AF_INET, SOCK_STREAM|SOCK_NONBLOCK, 0); printf("sockfd: %d\n", sockfd); struct sockaddr_in sin; sin.sin_family = AF_INET; sin.sin_port = htons(80); sin.sin_addr.s_addr = inet_addr("192.168.1.2"); socklen_t socklen = sizeof(struct sockaddr); int ret = connect(sockfd, (struct sockaddr*)&sin, socklen); printf("connect ret: %d\n", ret); if(ret != 0) {if(errno == EINPROGRESS){fd_set writefds;FD_ZERO(&writefds);FD_SET(sockfd, &writefds);struct timeval stm;stm.tv_sec = 3;stm.tv_usec = 0;ret = select(sockfd+1, NULL, &writefds, NULL, &stm);printf("select ret: %d\n", ret);//没有写事件,表示连接超时//比如,对端不可达if(0 == ret){printf("connect time out\n");}//有一个写事件else if (1 == ret){if(FD_ISSET(sockfd, &writefds)){printf("fd is set\n");//连接成功时val为0//连接失败时val非0,比如对端没有绑定该端口,val返回111,连接拒绝int val;ret = getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &val, &socklen);printf("getsockopt ret: %d\n", ret);printf("err code: %d, [%s]\n", val, strerror(val));}}}else{printf("%s\n", strerror(errno));}}close(sockfd); return 0;}
来源地址:https://blog.csdn.net/dreamflyly/article/details/129580846