TCP连接超时处理

        在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<sys/socket.h>
#include<sys/select.h>
#include<string.h>
#include<stdio.h>
#include<arpa/inet.h>
#include<errno.h>

int 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;
}

下面是我的微信公众号,欢迎大家关注

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值