简介

我们在使用客户端和服务器端连接的过程中,可能会因为各种问题导致客户端和服务器的连接发生中断,遇到这种情况,一般情况下我们需要使用监控程序去监听客户端和服务器端的连接,如果第一时间发现连接断开了,就需要手动去重连。比较麻烦,今天给大家介绍一种netty中自动重连的方式。

使用netty建立连接

要使用netty建立连接,首先需要启动服务器,通常来说服务器通过使用ServerBootstrap来启动服务器,如下所示:

// 绑定端口并启动
ChannelFuture f = b.bind(PORT).sync();

对于客户端来说,可以通过Bootstrap按如下的方式启动:

// 连接服务器
ChannelFuture f = b.connect(HOST, PORT).sync();

自动重连接的原理

那么当客户端和服务器端的连接断了之后,如何自动重连呢?

对于客户端来说,自动重连只需要再次调用Bootstrap的connect方法即可。现在的关键问题在于,如何找到重新调用connect的时机。

我们知道,不论server还是client,对于消息的处理都需要注册专门处理消息的handler。

对于读取消息来说,一般需要继承ChannelInboundHandlerAdapter,在这个handler中定义了很多和channel生命周期有关的方法,我们可以从这些生命周期的方法入手。

一般来说客户端和服务器连接的状态是这的:

CHANNEL REGISTERED--》CHANNEL ACTIVE --》 READ --》READ COMPLETE --》 CHANNEL INACTIVE --》 CHANNEL UNREGISTERED

客户端和服务器端的连接如果关闭的话,则会触发CHANNEL INACTIVE 和 CHANNEL UNREGISTERED 两个事件,这样我们在客户端重写下面两个方法,在方法中加入重连的逻辑即可。

    @Override
public void channelInactive(final ChannelHandlerContext ctx) {
println("连接断开:" + ctx.channel().remoteAddress());
} @Override
public void channelUnregistered(final ChannelHandlerContext ctx) throws Exception {
println("sleep:" + ReconnectClient.RECONNECT_DELAY + 's'); ctx.channel().eventLoop().schedule(() -> {
println("重连接: " + ReconnectClient.HOST + ':' + ReconnectClient.PORT);
ReconnectClient.connect();
}, ReconnectClient.RECONNECT_DELAY, TimeUnit.SECONDS);
}

在channelInactive方法中,我们只是打印了一些日志。主要逻辑在channelUnregistered方法中,在这个方法中我们首先通过ctx获取到当前的channel,然后拿到channel中的eventLoop,然后调用它的schedule方法,在给定的时间后重新调用connect()方法。

connect()方法返回的是一个ChannelFuture,所以可以在ChannelFuture中添加一些listener用来监听connect的执行状态。

这里定义的connect方法如下:

    static void connect() {
bs.connect().addListener(future -> {
if (future.cause() != null) {
handler.startTime = -1;
handler.println("建立连接失败: " + future.cause());
}
});
}

模拟自动重连

上一节我们已经知道怎么自动重连了,本小节将会对自动重连进行一个模拟。

这里要介绍一个类,叫做IdleStateHandler,从名字就可以看出来这个类是当 Channel 没有做任何read, write操作的时候,就会触发这个Idle的状态。

表示Idle状态的类叫做IdleStateEvent,Idle有6个状态,分别是FIRST_READER_IDLE_STATE_EVENT,READER_IDLE_STATE_EVENT,FIRST_WRITER_IDLE_STATE_EVENT,WRITER_IDLE_STATE_EVENT,FIRST_ALL_IDLE_STATE_EVENT和ALL_IDLE_STATE_EVENT。

分别表示读取状态的IDLE,写状态的IDLE和读写状态的IDLE。

这样我们在client启动的时候就可以加上IdleStateHandler,当client一段时间没有读取到server端发来的消息的时候,我们就调用ctx.close()将channel关闭,从而出发client端的重连操作。

        bs.group(group)
.channel(NioSocketChannel.class)
.remoteAddress(HOST, PORT)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new IdleStateHandler(READ_TIMEOUT, 0, 0), handler);
}
});

IdleStateEvent是一个用户出发的event,要捕获到这个event,需要重写userEventTriggered:

    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) {
if (!(evt instanceof IdleStateEvent)) {
return;
}
IdleStateEvent e = (IdleStateEvent) evt;
if (e.state() == IdleState.READER_IDLE) {
// 在Idle状态
println("Idle状态,关闭连接");
ctx.close();
}
}

上面的例子中,我们捕获了IdleStateEvent,并判断如果IdleState的状态是IdleState.READER_IDLE,那么就将channel关闭。

总结

本文我们介绍了重连的原理和用户触发的Event,希望大家能够喜欢。

本文的例子可以参考:learn-netty4

本文已收录于 http://www.flydean.com/09-netty-reconnect/

最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧等你来发现!

欢迎关注我的公众号:「程序那些事」,懂技术,更懂你!

netty系列之:自动重连的更多相关文章

  1. Netty 自动重连

    from: http://www.dozer.cc/2015/05/netty-auto-reconnect.html 自动重连 用 Netty 写 Client 和 Server 的时候必须要去处理 ...

  2. Netty系列之Netty可靠性分析

      作者 李林锋 发布于 2014年6月19日 | 29 讨论 分享到:微博微信FacebookTwitter有道云笔记邮件分享 稍后阅读 我的阅读清单   1. 背景 1.1. 宕机的代价 1.1. ...

  3. Spring-Data-Redis 下实现jedis连接断开后自动重连

    原先使用jedis的时候,处理手段是在从连接池获取连接时捕获JedisConnectionException异常,在异常处理部分重新获取连接,但是spring data redis似乎不会,如下所示: ...

  4. Netty系列(四)TCP拆包和粘包

    Netty系列(四)TCP拆包和粘包 一.拆包和粘包问题 (1) 一个小的Socket Buffer问题 在基于流的传输里比如 TCP/IP,接收到的数据会先被存储到一个 socket 接收缓冲里.不 ...

  5. Netty 系列(三)Netty 入门

    Netty 系列(三)Netty 入门 Netty 是一个提供异步事件驱动的网络应用框架,用以快速开发高性能.高可靠性的网络服务器和客户端程序.更多请参考:Netty Github 和 Netty中文 ...

  6. 【读后感】Netty 系列之 Netty 高性能之道 - 相比 Mina 怎样 ?

    [读后感]Netty 系列之 Netty 高性能之道 - 相比 Mina 怎样 ? 太阳火神的漂亮人生 (http://blog.csdn.net/opengl_es) 本文遵循"署名-非商 ...

  7. Netty系列之Netty可靠性分析--转载

    原文地址:http://www.infoq.com/cn/articles/netty-reliability 1. 背景 1.1. 宕机的代价 1.1.1. 电信行业 毕马威国际(KPMG Inte ...

  8. 3. 彤哥说netty系列之Java BIO NIO AIO进化史

    你好,我是彤哥,本篇是netty系列的第三篇. 欢迎来我的公从号彤哥读源码系统地学习源码&架构的知识. 简介 上一章我们介绍了IO的五种模型,实际上Java只支持其中的三种,即BIO/NIO/ ...

  9. 4. 彤哥说netty系列之Java NIO实现群聊(自己跟自己聊上瘾了)

    你好,我是彤哥,本篇是netty系列的第四篇. 欢迎来我的公从号彤哥读源码系统地学习源码&架构的知识. 简介 上一章我们一起学习了Java中的BIO/NIO/AIO的故事,本章将带着大家一起使 ...

随机推荐

  1. layui 监听checkbox 、radio、switch选中改变事件

    form.on('checkbox(filter)', function(data){ console.log(data.elem); //得到checkbox原始DOM对象 console.log( ...

  2. 安卓手机改造服务器——基本环境配置(CentOS7 arm32)

    安装好CentOS系统之后,我们需要对环境进行一些基本的配置,让Linux更好用 写在前面 注意:本文章是针对arm32的CentOS7进行配置的,其他系统或不同架构不要尝试. 配置yum镜像源 1. ...

  3. Hadoop:Hadoop的安装

    CentOS7安装Hadoop需要有JDK,所以先下载安装JDK后,在进行安装Hadoop 下载Hadoop #联网状态下使用wget命令 wget http://archive.apache.org ...

  4. springboot集成swagger添加消息头(header请求头信息)

    springboot集成swagger上篇文章介绍: https://blog.csdn.net/qiaorui_/article/details/80435488 添加头信息: package co ...

  5. 注解+AOP实现redis遍历缓存

    1.注解 package com.yun.smart.annotation; import java.lang.annotation.ElementType; import java.lang.ann ...

  6. 微信app支付,完整流程,完整代码 (转)

    微信app支付流程 需要的配置参数 private function wechat($body,$indent_id,$cou,$user_id,$total_fee,$ip,$domain,$non ...

  7. Local dimming algorithm in matlab plus 1

    (续)LED局部背光算法MATLAB仿真 在上一篇博客<Local dimming algorithm in matlab>中,我们实现了对一篇论文的算法用matlab仿真.在本篇论文中, ...

  8. 阿里云低延时直播 RTS 能力升级 让直播推流效果更佳

    行业背景 直播技术飞速发展让各个行业的用户体验呈现多样化和个性化,不同业务场景下创新实践满足大众对于音视频互动体验和参与的高标准要求.历经2020年初的巨变之后,以视频.游戏.电商.教育为主的互联网经 ...

  9. 修改vcenter的Administrator@vsphere.local密码

    vsphere 忘记vcenter的Administrator@vsphere.local密码的解决办法 1.cd  c:\Program Files\VMware\Infrastructure\VM ...

  10. 关闭火狐浏览器中的Pocket功能

    在火狐(Firefox)浏览器中,默认右键菜单和菜单栏都会有 Pocket按钮 .但是大部分国内用户都不会使用Pocket服务,看着还十分碍眼. 在工具栏的图标还可以通过定制工具栏修改,但是右键菜单中 ...