Detection of Half-Open (Dropped) Connections判断掉线半开连接

19 篇文章 0 订阅
4 篇文章 0 订阅

refs:

https://blog.stephencleary.com/2009/05/detection-of-half-open-dropped.html

https://superuser.com/questions/298919/what-is-tcp-half-open-connection-and-tcp-half-closed-connection

https://en.wikipedia.org/wiki/Transmission_Control_Protocol#Connection_establishment

这篇文章结合过去实践确实遇到相似的情景,只是之前不太明白原因。

 

用三路握手信号来打开一个tcp/ip连接,用四路握手信号去关闭连接。一旦连接建立,任何一方不发送数据,tcp将处于"idle"空闲状态。

TCP设计为有弹性和高效的.这个设计使得它能从网络插拔和路由重启中恢复过来。例如,一个客户端连着服务器,如果中间的路由重启了,当路由恢复后,原来的链接是仍然存在的(除非在路由宕机的时候发送数据)。因为这种高效设计,使得不需要发送“polling"包 来检查连接是否依然完好(减少了网络通讯负载)。

TCP对数据有应答机制,所以当一方发送数据到另一端,它将收到这个链接是否完好的应答。因此,连接断开可以用对外发送数据来判断。要注意的是,在TCP中,接收行为是完全被动的,一个只读取的socket是无法检测到连接的断开。

这导致了一个半开连接场景("half-open connection")。假设一个场景,在某一时刻,如果发送端和接收端之间的路由突然重启了,接收方继续等待消息到来,发送方继续发送数据,而发送方会受到一个错误,表示连接断开了。因此端口的连接可以被发送方通过发送数据检测到,而接收方会一直等下去。这个半开连接场景也因此得名。

导致半开连接的原因:

导致半开的原因是因为没有或没能按照协议实现四路握手断开连接。一些常见情景的如下:

1)进程crash,app异常中断,或有任务管理器关闭,这种情况一般操作系统会代替发送"FIN"包,但这取决于操作系统

2)计算机异常死机或断电,操作系统都挂了,并且么密友数据通信。

3)网线拔了,本地计算机一般会检测到断开,并通知;但远程的那端就未必了。

4)无线设备在信号区域外,丢失连接。

以上情景都是一方可能会知晓断开,而另一方不知。

半开连接检测是否必要?

有很多情景不需要,比如”Poll“系统,已经有定时器不停的poll,定时发送数据,所以不需要。

另外是否必要需要根据连接双方的需求来,在”Poll“系统中,poll的一方就不需要了,另一方相应polling的可能需要keepalive的握手实现。

如何检测到半开连接?

略掉 作者例子和错误示例(即不要用 第二个socket去解决这个问题;不要用ping来解决,协议不同);

正确的检测掉线连接的方法:

这儿有几种方法,每个都有自己的优缺点,一下按最优~最糟糕排序:

1)添加一个keepalive消息协议。可以长度固定,发送空消息,如0字节。

优点:上层协议不受影响

缺点:要求连接双方都有修改,如果协议已经固定或不能增加,则不适用。

2)添加一个keepalive消息到真实的应用协议中,他添加了新的空消息(null message)到应用协议中。

优点:如果应用协议使用非正式消息帧系统。这种情况方法1 也不能被使用。

缺点:类似方法1,要求通信双方都有改动。如果协议不能改变也无法使用。

3)定时器检测。设置一个超时定时器,有数据到复位,如果超时则认为连接断开了。http 服务器即是用这种方式。

优点:不需要修改应用协议,不同于前2者。另外减少了网络负载,它不需要发送数据来保持连接。

缺点:决定于协议,可能有一堆有效链接会被中断。(如果长期没有数据传输)

4)修改tcp/ip keepalive包的设置。这是一个高级解决方案,需要修改一系列参数。在 stevens的书第23章中有讨论(https://blog.stephencleary.com/2009/05/tcpip-resources.html)。结果导致tcp/ip 栈 因为应用程序的缘故去定时发送keepalive 包。

优点:一旦keepalive参数设置生效,应用程序无需任何修改。

缺点:RFC1122协议第4.2.3.6章节 表明 TCP keepalive的没有数据的响应不能被路由可靠传输;这可能导致有效链接被中断。另外 TCP/IP栈并不要求一定要支持keepalive协议(特别是嵌入式设备上),所以这个方案有其局限性。

有两种方法来实现方案4

4)1)设置 SocketOptionName.KeepAlive 参数,MSDN文档没有明确,默认可能是2小时。通过注册表键值可以被修改,但这是全局的参数,意味着所有系统上的应用都会受影响。这种修改方式是过去传统的实现方法。

4)2)设置 per-connection keepalives.  Keepalive 参数可以设置 per-connection 仅win2000及以后的系统。通过修改socket的io控制实现:通过随着Socket.IOControl传递 IOControlCode.KeepAliveValue值,这在.net 文档中没有描述,但在WSAIoctl (SIO_KEEPALIVE_VALS)中有记载。(https://docs.microsoft.com/zh-cn/windows/desktop/api/winsock2/nf-winsock2-wsaioctl

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值