简介

我们在使用客户端和服务器端连接的过程中,可能会因为各种问题导致客户端和服务器的连接发生中断,遇到这种情况,一般情况下我们需要使用监控程序去监听客户端和服务器端的连接,如果第一时间发现连接断开了,就需要手动去重连。比较麻烦,今天给大家介绍一种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. 测试开发:推荐一款阿里最新 Python 自动化开源工具!

    大家好,我是麦小米,是狂师老师全栈测开训练营中的一名学员. 如果之前做过iOS自动化的同学相信都知道,一直以来,iOS自动化的实现&执行都必须依赖 Mac 系统,其主要原因是因为需要通过 xc ...

  2. 23、swap分区扩充

    23.1.使用fdisk创建构建sapw: fdisk /dev/sdb=>分一个主分区/dev/sdb1(同理也可以使用parted mbr模式和parted gpt模式构建一个主分区) pa ...

  3. InterlliJ Debug启动提示:Method breakpoints may dramatically slow down debugging

  4. json串向后台传递数值自动四舍五入的问题

    业务需求:传递前台输入的数据,数量要求是小数点(多条数据) 后台服务是使用asp.net写的. 问题:反序列化JSON时总是自动四舍五入. 原因:JSON反序列化的时候数据类型是以第一条数据的类型为准 ...

  5. SonarQube插件

    关于插件我本身使用不多,如果看不惯英文界面,那么就先装个中文插件吧. 或者上微软的官方网站进行下载 将下载的插件上传到自己的sonarqube的服务的机器上,放置插件目录下,重启sonarqube即可 ...

  6. 使用IDEA配置Maven

    IDEA中配置Maven File --> settings 推荐配置:设置maven在不联网的情况下使用本地插件 一般使用maven为我们提供好的骨架时,是需要联网的,配置这个,可以在没有网络 ...

  7. Python管道进行数据的吞吐处理

    import multiprocessing import random import time import datetime import struct import os import getF ...

  8. Mybatis学习(7)实现mybatis分页

    上一篇文章里已经讲到了mybatis与spring MVC的集成,并且做了一个列表展示,显示出所有article 列表,但没有用到分页,在实际的项目中,分页是肯定需要的.而且是物理分页,不是内存分页. ...

  9. MySQL 卡死的问题

    1. 执行show full processlist观察state和info两列,查看有哪些线程在运行. 2.使用kill命令+对应线程前面id杀死卡死的线程. 其他的方式: -- 查询是否锁表 sh ...

  10. easyui的combobox的onChange事件的实现

    easyui的combobox的onChange事件的实现,直接上代码: <div style="display:inline;margin-left:15px;"> ...