开发im即时通讯如何用Netty实现心跳机制、断线重连机制

王一贴
• 阅读 121

所谓心跳, 即在 TCP 长连接中, 客户端和服务器之间定期发送的一种特殊的数据包, 通知对方自己还在线, 以确保 TCP 连接的有效性。

注:心跳包还有另一个作用,经常被忽略,即:一个连接如果长时间不用,防火墙或者路由器就会断开该连接(PS:术语叫“端口老化”)。

先理解一下核心Handler:IdleStateHandler

在 Netty 中, 实现心跳机制的关键是 IdleStateHandler, 那么这个 Handler 如何使用呢?

先看下它的构造器

开发im即时通讯如何用Netty实现心跳机制、断线重连机制

public IdleStateHandler(int readerIdleTimeSeconds, int writerIdleTimeSeconds, int allIdleTimeSeconds) {

this((long)readerIdleTimeSeconds, (long)writerIdleTimeSeconds, (long)allIdleTimeSeconds, TimeUnit.SECONDS);

}

这里解释下三个参数的含义:

readerIdleTimeSeconds: 读超时. 即当在指定的时间间隔内没有从 Channel 读取到数据时, 会触发一个 READER_IDLE 的 IdleStateEvent 事件.

writerIdleTimeSeconds: 写超时. 即当在指定的时间间隔内没有数据写入到 Channel 时, 会触发一个 WRITER_IDLE 的 IdleStateEvent 事件.

allIdleTimeSeconds: 读/写超时. 即当在指定的时间间隔内没有读或写操作时, 会触发一个 ALL_IDLE 的 IdleStateEvent 事件.

注:这三个参数默认的时间单位是秒。若需要指定其他时间单位,可以使用另一个构造方法:IdleStateHandler(boolean observeOutput, long readerIdleTime, long writerIdleTime, long allIdleTime, TimeUnit unit)

下面将使用IdleStateHandler来实现心跳,Client端连接到Server端后,会循环执行一个任务:随机等待几秒,然后ping一下Server端,即发送一个心跳包。

当等待的时间超过规定时间,将会发送失败,以为Server端在此之前已经主动断开连接了。

实现代码如下。

ClientIdleStateTrigger —— 心跳触发器:

类ClientIdleStateTrigger也是一个Handler,只是重写了userEventTriggered方法,用于捕获IdleState.WRITER_IDLE事件(未在指定时间内向服务器发送数据),然后向Server端发送一个心跳包。

首先启动客户端,再启动服务器端。

可以看到,客户端在发送4个心跳包后,第5个包因为等待时间较长,等到真正发送的时候,发现连接已断开了;而服务器端收到客户端的4个心跳数据包后,迟迟等不到下一个数据包,所以果断断开该连接。

出现这种情况的原因是:在连接已断开的情况下,仍然向服务器端发送心跳包。虽然在发送心跳包之前会使用 channel.isActive() 判断连接是否可用,但也有可能上一刻判断结果为可用,但下一刻发送数据包之前,连接就断了。即时通讯聊天软件app开发可以咨询蔚可云。

开发im即时通讯如何用Netty实现心跳机制、断线重连机制

目前尚未找到优雅处理这种情况的方案,各位看官如果有好的解决方案,还望不吝赐教。拜谢!

断线重连对于复杂网络非常有用(没有这个,一旦断网,通信就无法自动恢复了),这里就不过多介绍,相信各位都知道是怎么回事。这里只说大致思路,然后直接上代码。

客户端在监测到与服务器端的连接断开后,或者一开始就无法连接的情况下,使用指定的重连策略进行重连操作,直到重新建立连接或重试次数耗尽。

对于如何监测连接是否断开,则是通过重写ChannelInboundHandler#channelInactive来实现,但连接不可用,该方法会被触发,所以只需要在该方法做好重连工作即可。

可以看到,当客户端发现无法连接到服务器端,所以一直尝试重连。随着重试次数增加,重试时间间隔越大,但又不想无限增大下去,所以需要定一个阈值,比如60s。如上图所示,当下一次重试时间超过60s时,会打印Sleep

extension too large(*). Pinning to 60000,单位为ms。出现这句话的意思是,计算出来的时间超过阈值(60s),所以把真正睡眠的时间重置为阈值(60s)。

可以看到,在第9次重试失败后,第10次重试之前,启动的服务器,所以第10次重连的结果为Successfully established a connection to the server.,即成功连接到服务器。接下来因为还是不定时ping服务器,所以出现断线重连、断线重连的循环。

在不同环境,可能会有不同的重连需求。有不同的重连需求的,只需自己实现RetryPolicy接口,然后在创建TcpClient的时候覆盖默认的重连策略即可。

点赞
收藏
评论区
推荐文章
亚瑟 亚瑟
4年前
php操作redis哨兵模式,主从切换后自动获取master
本文将介绍如何使用PHP来连接redis哨兵模式。哨兵模式:大概的原理就是监听redis主库心跳包,如果心跳断开,则枚举一个从库推举成为新的主库,防止redis宕机不能使用。为了增强redis的性能,防止其挂掉,引用redis哨兵监控redis集群是个不错的选择。下面三步简单记录php连接redis哨兵。第一步、获取哨兵模式连接redis句柄对象/
Stella981 Stella981
3年前
Netty干货分享:京东京麦的生产级TCP网关技术实践总结
1、引言京东的京麦商家后台2014年构建网关,从HTTP网关发展到TCP网关。在2016年重构完成基于Netty4.xProtobuf3.x实现对接PC和App上下行通信的高可用、高性能、高稳定的TCP长连接网关。早期京麦搭建HTTP和TCP长连接功能主要用于消息通知的推送,并未应用于API网关。随着逐步对NIO的深入学习和对Netty框
Easter79 Easter79
3年前
TCP漫谈之keepalive和time_wait
TCP是一个有状态通讯协议,所谓的有状态是指通信过程中通信的双方各自维护连接的状态。一、TCPkeepalive先简单回顾一下TCP连接建立和断开的整个过程。(这里主要考虑主流程,关于丢包、拥塞、窗口、失败重试等情况后面详细讨论。)首先是客户端发送syn(SynchronizeSequenceNumbers:
Stella981 Stella981
3年前
Netty解决TCP粘包和拆包问题的四种方案
 在RPC框架中,TCP粘包和拆包问题是必须解决一个问题,因为RPC框架中,各个微服务相互之间都是维系了一个TCP长连接,比如dubbo就是一个全双工的长连接。由于微服务往对方发送信息的时候,所有的请求都是使用的同一个连接,这样就会产生粘包和拆包的问题。本文首先会对TCP粘包和拆包问题进行描述,然后介绍其常用的解决方案,最后会对Netty提供的几种解决方案进
Wesley13 Wesley13
3年前
IM总结
发送消息UDP打洞,登录的时候HTTP。登录成功后,会有一个TCP连接来保持在线状态。这个TCP连接的远程端口一般是80,采用UDP方式登录的时候,端口是8000。如果采用UDP协议,通过服务器中转方式。UDP协议是不可靠协议,它只管发送,不管对方是否收到的。如果client使用UDP协议发送消息后,服务器收到该包,需要使用UDP协议发回一个
Stella981 Stella981
3年前
Netty(一) SpringBoot 整合长连接心跳机制
 https://github.com/crossoverJie/JCSprout原创: crossoverJie 阅读原文(https://www.oschina.net/action/GoToLink?urlhttps%3A%2F%2Fmp.weixin.qq.
Stella981 Stella981
3年前
Netty 如何实现心跳机制与断线重连?
作者:sprinkle\_lizwww.jianshu.com/p/1a28e48edd92心跳机制何为心跳所谓心跳,即在 TCP 长连接中,客户端和服务器之间定期发送的一种特殊的数据包,通知对方自己还在线,以确保 TCP 连接的有效性.注:心跳包还有另一个作用,经常被忽略,即:一个连接如果长时间不用,防
Stella981 Stella981
3年前
Netty 4.0 实现心跳检测和断线重连
一实现心跳检测原理:当服务端每隔一段时间就会向客户端发送心跳包,客户端收到心跳包后同样也会回一个心跳包给服务端一般情况下,客户端与服务端在指定时间内没有任何读写请求,就会认为连接是idle(空闲的)的。此时,客户端需要向服务端发送心跳消息,来维持服务端与客户端的链接。那么怎么判断客户端在指定时间里没有任何读写请求呢?netty中为我们提供一
Stella981 Stella981
3年前
Linux应急响应(二):捕捉短连接
0x00前言​短连接(shortconnnection)是相对于长连接而言的概念,指的是在数据传送过程中,只在需要发送数据时,才去建立一个连接,数据发送完成后,则断开此连接,即每次连接只完成一项业务的发送。在系统维护中,一般很难去察觉,需要借助网络安全设备或者抓包分析,才能够去发现。0x01应急场景​
Stella981 Stella981
3年前
C# Socket之异步TCP客户端断线重连
  我们知道TCP通信是一种面向连接的Socket,针对于面向连接的TCP服务应用,安全,但是效率低,它首先需要服务端开启服务,然后客户端才可以去连接,如果服务端没有开启通信服务或者连接之后再中途因为某些原因断开连接了,那么都是会通信失败的,所以我们这篇博客主要是对TCP通信加入两个机制。1,客户端开启后未连接成功,自动重连请求2,若通信途中因为某些原因断
Stella981 Stella981
3年前
Socket心跳机制
本文是我在实际工作中用到的Socket通信,关于心跳机制的维护方式,特意总结了一下,希望对朋友们有所帮助。Socket应用:首先Socket封装了tcp协议的,通过长连接的方式来与服务器通信,是由服务器和客户端两部分组成的,当客户端成功连接之后,服务器会记录这个用户,并为它分配资源,当客户端断开连接后,服务器会自动释放资源。但在实际的网络环
王一贴
王一贴
Lv1
一叫一回肠一断,三春三月忆三巴。
文章
4
粉丝
0
获赞
0