Linux系统下判断TCP连接状态的几种方法

当客户端与服务端保持长连接时,客户端除了可以使用心跳包来确认连接状态外,还可以使用一下几种方法:

一、使用recv() 函数判断连接状态

使用recv() 函数的MSG_PEEK选项,使用这个选项可以“偷看(peek)”一下接收队列的数据。所谓“偷看”,就是recv()不从接收队列中把数据移除,因此下一次调用recv()函数还会接收到此数据。
当TCP连接处于已建立Established状态时,如果接收队列中有数据,recv()函数返回1;如果接收队列中没有数据但是TCP连接没有断开,recv() 函数返回-1,并且把errno设置为EAGAIN。其余情况下表示TCP连接已经断开。

bool
tcp_connection_state(int fd) {
	char buf[1];
	int err;
	 
	err = recv(fd, buf, sizeof(buf), MSG_PEEK);
	if (err == 1 || (err == -1 && errno == EAGAIN)) {
		return true;
	}
	return false;
}

PS: 注意在获取errno时,也可以使用getsockopt(fd, SOL_SOCKET, SO_ERROR, &status, &status_len)来获取,SO_ERROR选项获得errno的值并且随后置零。

二、使用epoll异步监控连接状态

使用epoll监控socket连接时有两种情况下可以断定此连接已经断开:

  1. 当触发可读事件,但是接收字节数为0。这种情况下,FIN数据包在read()调用前,在EPOLLIN唤醒epoll后到达TCP被动关闭方。
  2. EPOLLRDHUP事件唤醒epoll_wait()函数,表示对端主动断开连接。注意当epoll事件返回为EPOLLHUP通常时socket内部错误,而不是连接主动断开。

三、使用getsockopt() 函数的TCP_INFO选项

bool
tcp_connection_state(int fd) {
	struct tcp_info info; 
  	int len=sizeof(info);
 
  	getsockopt(sock, IPPROTO_TCP, TCP_INFO, &info, (socklen_t *)&len);
  	if((info.tcpi_state==TCP_ESTABLISHED)) {
  		return true;
  	}
  	return false;
}

在没有使用read()write()epoll()时使用

四、使用TCP心跳处理

int keepAlive = 1; 		// 开启keepalive属性
int keepIdle = 60; 		// 如该连接在60秒内没有任何数据往来,则进行探测
int keepInterval = 5; 	// 探测时发包的时间间隔为5 秒
int keepCount = 3; 		// 探测尝试的次数.如果第1次探测包就收到响应了,则后2次的不再发.

setsockopt(rs, SOL_SOCKET, SO_KEEPALIVE, (void *)&keepAlive, sizeof(keepAlive));
setsockopt(rs, SOL_TCP, TCP_KEEPIDLE, (void*)&keepIdle, sizeof(keepIdle));
setsockopt(rs, SOL_TCP, TCP_KEEPINTVL, (void *)&keepInterval, sizeof(keepInterval));
setsockopt(rs, SOL_TCP, TCP_KEEPCNT, (void *)&keepCount, sizeof(keepCount));

设置后,若断开,则在使用该socket读写时立即失败,并返回ETIMEDOUT错误。但是上述方法有个重试次数,tcp连接状态检测检测有滞后性。在linux kernel 2.6.37版本后,支持TCP_USER_TIME_OUT选项,超时后直接判断连接超时。

unsigned int timeout = 1000;   //值为数据包被发送后未接收到ACK确认的最大时长,以毫秒
                               //为单位,例如设置为timeout时,代表如果发送出去的数据包
                               //在timeout毫秒内未收到ACK确认,则下一次调用send或者recv,
                               //函数会返回-1,errno设置为ETIMEOUT,代表connection timeout。

    //使用TCP Keep-alive加上TCP_USER_TIMEOUT机制,就可以完美解
    //决通信对端异常断网、掉电的情况下,连接被长期挂起的问题了。
    setsockopt(socket_fd, IPPROTO_TCP, TCP_USER_TIMEOUT, &timeout, sizeof(timeout));

五、使用七层心跳处理

有时服务端程序停止服务,但是内核还维护着TCP连接。在这种情况下,使用7层的心跳处理是有效的,

参考


大家对此问题有什么想法,欢迎讨论。加油,打工人!

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值