简介

我们在使用客户端和服务器端连接的过程中,可能会因为各种问题导致客户端和服务器的连接发生中断,遇到这种情况,一般情况下我们需要使用监控程序去监听客户端和服务器端的连接,如果第一时间发现连接断开了,就需要手动去重连。比较麻烦,今天给大家介绍一种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. 一、JavaSE语言基础之关键字与标示符

    1.关键字   所谓关键字指Java中被赋予了特殊含义的单词或字符,Java中常见的关键字共53个,不需要进行记忆,在写代码的过程中会逐渐接触. 2.标示符   标示符,简单来说就是名字:其最大的作用 ...

  2. Python | 更换pip源到国内镜像

    pip国内的一些镜像 阿里云 https://mirrors.aliyun.com/pypi/simple/ 中国科技大学 https://pypi.mirrors.ustc.edu.cn/simpl ...

  3. Docker:Linux离线安装docker

    docker离线下载路径 docker所有版本:https://download.docker.com/linux/static/stable/ 离线安装 1.解压 #解压tar包 tar -xvf ...

  4. Spring:Spring嵌套事务方式

    Spring遇到嵌套事务时,怎么实现 实验时却遇到一个奇怪的问题: 1.当ServiceA.a()方法调用ServiceB.b()方法时,内层事务提交和回滚,都不受外层事务提交或回滚的影响. 2.当S ...

  5. phpstorm之"Can not run PHP Code Sniffer"

    前言 其实我是不太愿意写这种工具使用博客的,因为实在没有营养,只是有些简单问题,搜索一番,却始终找不到答案,遂以博客记录下来,希望后面的人,可以省去搜索之苦. 相信你搜到这篇博客,肯定是已经安装好了P ...

  6. buu crypto 凯撒?替换?呵呵!

    一. 以为是简单的凯撒加密,但是分析Ascill表,发现毫无规律,意味着要爆破出所有可能.只能用在线工具来弄了,脚本是不可能写的(狗头) 找到了,但是提交不成功,需要变成小写,用脚本转换一下,同时很坑 ...

  7. linux中如何添加用户并赋予root权限详解

    #adduser username 修改 /etc/sudoers 文件,找到下面一行,在root下面添加一行,如下所示: ## Allow root to run any commands anyw ...

  8. HMAC简介及HMAC-SHA256实现Demo

    一.什么是HMAC HMAC是一种使用单向散列函数来构造消息认证码的方法,其中HMAC中的H就是Hash的意思. HMAC中所使用的单向散列函数并不仅限于一种,任何高强度的单向散列函数都可以被用于HM ...

  9. python使用笔记24--面向对象编程2

    类方法 类里面自带的方法,不用实例化就可以调用,想象,模型上自带的功能 类方法是公共的,在实例方法里面可以随意调用 但是在类方法里不能调用实例方法,不能使用实例变量,但是他可以调用其他的类方法 1 @ ...

  10. python使用笔记15--操作Excel

    python操作Excel需要引入第三方模块 执行以下命令: pip install xlwt pip install xlrd pip install xlutils 1.写Excel 1 impo ...