netty主动断开连接_使用Netty实现 IM 聊天贼简单,看不懂就锤爆哪吒的狗头~(结局)...

本文介绍了如何使用Netty实现IM聊天应用的断开重连和心跳机制。针对不同断开场景,Netty客户端通过定时重连确保连接稳定。在心跳机制部分,介绍了服务端和客户端的空闲检测,以及如何通过HeartbeatRequest和HeartbeatResponse维持连接活跃。此外,还涵盖了认证逻辑和简单的测试案例。
摘要由CSDN通过智能技术生成

5. 断开重连

Netty 客户端需要实现断开重连机制,解决各种情况下的断开情况。例如说:

  • Netty 客户端启动时,Netty 服务端处于挂掉,导致无法连接上。
  • 在运行过程中,Netty 服务端挂掉,导致连接被断开。
  • 任一一端网络抖动,导致连接异常断开。

具体的代码实现比较简单,只需要在两个地方增加重连机制。

  • Netty 客户端启动时,无法连接 Netty 服务端时,发起重连。
  • Netty 客户端运行时,和 Netty 断开连接时,发起重连。

考虑到重连会存在失败的情况,我们采用定时重连的方式,避免占用过多资源。

5.1 具体代码

① 在 NettyClient 中,提供 #reconnect() 方法,实现定时重连的逻辑。代码如下:

// NettyClient.javapublic void reconnect() {    eventGroup.schedule(new Runnable() {        @Override        public void run() {            logger.info("[reconnect][开始重连]");            try {                start();            } catch (InterruptedException e) {                logger.error("[reconnect][重连失败]", e);            }        }    }, RECONNECT_SECONDS, TimeUnit.SECONDS);    logger.info("[reconnect][{} 秒后将发起重连]", RECONNECT_SECONDS);}

通过调用 EventLoop 提供的 #schedule(Runnable command, long delay, TimeUnit unit) 方法,实现定时逻辑。而在内部的具体逻辑,调用 NettyClient 的 #start() 方法,发起连接 Netty 服务端。

又因为 NettyClient 在 #start() 方法在连接 Netty 服务端失败时,又会调用 #reconnect()方法,从而再次发起定时重连。如此循环反复,知道 Netty 客户端连接上 Netty 服务端。如下图所示:

03ab5093bbde65d622e7b518eb9f5762.png

NettyClient 重连

② 在 NettyClientHandler 中,实现 #channelInactive(ChannelHandlerContext ctx) 方法,在发现和 Netty 服务端断开时,调用 Netty Client 的 #reconnect() 方法,发起重连。代码如下:

// NettyClientHandler.java@Overridepublic void channelInactive(ChannelHandlerContext ctx) throws Exception {    // 发起重连    nettyClient.reconnect();    // 继续触发事件    super.channelInactive(ctx);}

5.2 简单测试

① 启动 Netty Client,不要启动 Netty Server,控制台打印日志如下图:

2bf6fcbd240d216604a4d1ea6e42b0e8.png

重连失败

可以看到 Netty Client 在连接失败时,不断发起定时重连。

② 启动 Netty Server,控制台打印如下图:

13f9cd5543fd684758ec942fd5920796.png

重连成功

可以看到 Netty Client 成功重连上 Netty Server。

6. 心跳机制与空闲检测

在上文中,艿艿推荐胖友阅读《TCP Keepalive 机制刨根问底》文章,我们可以了解到 TCP 自带的空闲检测机制,默认是 2 小时。这样的检测机制,从系统资源层面上来说是可以接受的。

但是在业务层面,如果 2 小时才发现客户端与服务端的连接实际已经断开,会导致中间非常多的消息丢失,影响客户的使用体验。

因此,我们需要在业务层面,自己实现空闲检测,保证尽快发现客户端与服务端实际已经断开的情况。实现逻辑如下:

  • 服务端发现 180 秒未从客户端读取到消息,主动断开连接。
  • 客户端发现 180 秒未从服务端读取到消息,主动断开连接。

考虑到客户端和服务端之间并不是一直有消息的交互,所以我们需要增加心跳机制

  • 客户端每 60 秒向服务端发起一次心跳消息,保证服务端可以读取到消息。
  • 服务端在收到心跳消息时,回复客户端一条确认消息,保证客户端可以读取到消息。

友情提示:

为什么是 180 秒?可以加大或者减小,看自己希望多快检测到连接异常。过短的时间,会导致心跳过于频繁,占用过多资源。

为什么是 60 秒?三次机会,确认是否心跳超时。

虽然听起来有点复杂,但是实现起来并不复杂哈。

6.1 服务端的空闲检测

在 NettyServerHandlerInitializer 中,我们添加了一个 ReadTimeoutHandler 处理器,它在超过指定时间未从对端读取到数据,会抛出 ReadTimeoutException 异常。如下图所示:

d2bc3071c165265d8dfbcdb8550086bd.png

ReadTimeoutHandler

通过这样的方式,实现服务端发现 180 秒未从客户端读取到消息,主动断开连接。

6.2 客户端的空闲检测

友情提示:和「6.1 服务端的空闲检测」一致。

在 NettyClientHandlerInitializer 中,我们添加了一个 ReadTimeoutHandler 处理器,它在超过指定时间未从对端读取到数据,会抛出 ReadTimeoutException 异常。如下图所示:

bc19b3a9cd5438f3683a59a04c9cb45f.png

ReadTimeoutHandler

通过这样的方式,实现客户端发现 180 秒未从服务端读取到消息,主动断开连接。

6.3 心跳机制

Netty 提供了 IdleStateHandler 处理器,提供空闲检测的功能,在 Channel 的读或者写空闲时间太长时,将会触发一个 IdleStateEvent 事件。

这样,我们只需要在 NettyClientHandler 处理器中,在接收到 IdleStateEvent 事件时,客户端向客户端发送一次心跳消息。如下图所示:

cb84b7f1ef6ee1e05f21b10f0872c9ad.png

客户端心跳

  • 其中,HeartbeatRequest 是心跳请求。

同时,我们在服务端项目中,创建了一个 HeartbeatRequestHandler 消息处理器,在收到客户端的心跳请求时,回复客户端一条确认消息。代码如下:

@Componentpublic class HeartbeatRequestHandler implements MessageHandler {    private Logger logger = LoggerFactory
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值