热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

netty心跳过程中发送消息失败_Netty4.0实现心跳检测和断线重连

arg0.pipeline().addLast(ping,newIdleStateHandler(25,15,10,TimeUnit.SECONDS));这个处理器࿰

arg0.pipeline().addLast("ping", new IdleStateHandler(25, 15, 10,TimeUnit.SECONDS));

这个处理器,它的作用就是用来检测客户端的读取超时的,该类的第一个参数是指定读操作空闲秒数,第二个参数是指定写操作的空闲秒数,第三个参数是指定读写空闲秒数,当有操作操作超出指定空闲秒数时,便会触发UserEventTriggered事件。所以我们只需要在自己的handler中截获该事件,然后发起相应的操作即可(比如说发起心跳操作)。以下是我们自定义的handler中的代码:

/**

* 一段时间未进行读写操作 回调

*/

@Override

public void userEventTriggered(ChannelHandlerContext ctx, Object evt)

throws Exception {

// TODO Auto-generated method stub

super.userEventTriggered(ctx, evt);

if (evt instanceof IdleStateEvent) {

IdleStateEvent event = (IdleStateEvent) evt;

if (event.state().equals(IdleState.READER_IDLE)) {

//未进行读操作

System.out.println("READER_IDLE");

// 超时关闭channel

ctx.close();

} else if (event.state().equals(IdleState.WRITER_IDLE)) {

} else if (event.state().equals(IdleState.ALL_IDLE)) {

//未进行读写

System.out.println("ALL_IDLE");

// 发送心跳消息

MsgHandleService.getInstance().sendMsgUtil.sendHeartMessage(ctx);

}

}

}

也就是说 服务端在10s内未进行读写操作,就会向客户端发送心跳包,客户端收到心跳包后立即回复心跳包给服务端,此时服务端就进行了读操作,也就不会触发IdleState.READER_IDLE(未读操作状态),若客户端异常掉线了,并不能响应服务端发来的心跳包,在25s后就会触发IdleState.READER_IDLE(未读操作状态),此时服务器就会将通道关闭

客户端代码略

二 客户端实现断线重连

原理当客户端连接服务器时

bootstrap.connect(new InetSocketAddress(

serverIP, port));

会返回一个ChannelFuture的对象,我们对这个对象进行监听

代码如下:

import android.os.Handler;

import android.os.HandlerThread;

import android.os.Message;

import android.util.Log;

import com.ld.qmwj.Config;

import com.ld.qmwj.MyApplication;

import java.net.InetSocketAddress;

import java.nio.charset.Charset;

import java.util.concurrent.TimeUnit;

import io.netty.bootstrap.Bootstrap;

import io.netty.buffer.ByteBuf;

import io.netty.buffer.Unpooled;

import io.netty.channel.ChannelFuture;

import io.netty.channel.ChannelFutureListener;

import io.netty.channel.ChannelInitializer;

import io.netty.channel.ChannelOption;

import io.netty.channel.nio.NioEventLoopGroup;

import io.netty.channel.socket.SocketChannel;

import io.netty.channel.socket.nio.NioSocketChannel;

import io.netty.handler.codec.DelimiterBasedFrameDecoder;

import io.netty.handler.codec.string.StringDecoder;

import io.netty.handler.codec.string.StringEncoder;

/**

* Created by zsg on 2015/11/21.

*/

public class MyClient implements Config {

private static Bootstrap bootstrap;

private static ChannelFutureListener channelFutureListener = null;

public MyClient() {

}

// 初始化客户端

public static void initClient() {

NioEventLoopGroup group = new NioEventLoopGroup();

// Client服务启动器 3.x的ClientBootstrap

// 改为Bootstrap,且构造函数变化很大,这里用无参构造。

bootstrap = new Bootstrap();

// 指定EventLoopGroup

bootstrap.group(group);

// 指定channel类型

bootstrap.channel(NioSocketChannel.class);

// 指定Handler

bootstrap.handler(new ChannelInitializer() {

@Override

protected void initChannel(SocketChannel ch) throws Exception {

// 创建分隔符缓冲对象

ByteBuf delimiter = Unpooled.copiedBuffer("#"

.getBytes());

// 当达到最大长度仍没找到分隔符 就抛出异常

ch.pipeline().addLast(

new DelimiterBasedFrameDecoder(10000, true, false, delimiter));

// 将消息转化成字符串对象 下面的到的消息就不用转化了

//解码

ch.pipeline().addLast(new StringEncoder(Charset.forName("UTF-8")));

ch.pipeline().addLast(new StringDecoder(Charset.forName("GBK")));

ch.pipeline().addLast(new MyClientHandler());

}

});

//设置TCP协议的属性

bootstrap.option(ChannelOption.SO_KEEPALIVE, true);

bootstrap.option(ChannelOption.TCP_NODELAY, true);

bootstrap.option(ChannelOption.SO_TIMEOUT, 5000);

channelFutureListener = new ChannelFutureListener() {

public void operationComplete(ChannelFuture f) throws Exception {

// Log.d(Config.TAG, "isDone:" + f.isDone() + " isSuccess:" + f.isSuccess() +

// " cause" + f.cause() + " isCancelled" + f.isCancelled());

if (f.isSuccess()) {

Log.d(Config.TAG, "重新连接服务器成功");

} else {

Log.d(Config.TAG, "重新连接服务器失败");

// 3秒后重新连接

f.channel().eventLoop().schedule(new Runnable() {

@Override

public void run() {

doConnect();

}

}, 3, TimeUnit.SECONDS);

}

}

};

}

// 连接到服务端

public static void doConnect() {

Log.d(TAG, "doConnect");

ChannelFuture future = null;

try {

future = bootstrap.connect(new InetSocketAddress(

serverIP, port));

future.addListener(channelFutureListener);

} catch (Exception e) {

e.printStackTrace();

//future.addListener(channelFutureListener);

Log.d(TAG, "关闭连接");

}

}

}

监听到连接服务器失败时,会在3秒后重新连接(执行doConnect方法)

这还不够,当客户端掉线时要进行重新连接

在我们自己定义逻辑处理的Handler中

@Override

public void channelInactive(ChannelHandlerContext ctx) throws Exception {

Log.d(Config.TAG, "与服务器断开连接服务器");

super.channelInactive(ctx);

MsgHandle.getInstance().channel = null;

//重新连接服务器

ctx.channel().eventLoop().schedule(new Runnable() {

@Override

public void run() {

MyClient.doConnect();

}

}, 2, TimeUnit.SECONDS);

ctx.close();

}

3

1

分享到:

2016-02-17 21:42

浏览 30989

评论

3 楼

VIP庚

2016-12-23

sdtzyb 写道

MsgHandle 这个里面写的是什么为什么需要把        MsgHandle.getInstance().channel = null;

弄成空。

能不能把提懂点详细代码

channel是客户端与服务器之间通信的通道,和socket类似,当客户端与服务器连接成功后,会将chanel保存。这里是客户端与服务器断开连接后进行重连,所以要将原先的通道变成空

2 楼

sdtzyb

2016-12-21

MsgHandle 这个里面写的是什么为什么需要把        MsgHandle.getInstance().channel = null;

弄成空。

能不能把提懂点详细代码

1 楼

newboy2004

2016-04-21

对netty应用理解的更深入了一点



推荐阅读
  • 本文详细介绍了一种利用 ESP8266 01S 模块构建 Web 服务器的成功实践方案。通过具体的代码示例和详细的步骤说明,帮助读者快速掌握该模块的使用方法。在疫情期间,作者重新审视并研究了这一未被充分利用的模块,最终成功实现了 Web 服务器的功能。本文不仅提供了完整的代码实现,还涵盖了调试过程中遇到的常见问题及其解决方法,为初学者提供了宝贵的参考。 ... [详细]
  • 在Java Web服务开发中,Apache CXF 和 Axis2 是两个广泛使用的框架。CXF 由于其与 Spring 框架的无缝集成能力,以及更简便的部署方式,成为了许多开发者的首选。本文将详细介绍如何使用 CXF 框架进行 Web 服务的开发,包括环境搭建、服务发布和客户端调用等关键步骤,为开发者提供一个全面的实践指南。 ... [详细]
  • Netty框架中运用Protobuf实现高效通信协议
    在Netty框架中,通过引入Protobuf来实现高效的通信协议。为了使用Protobuf,需要先准备好环境,包括下载并安装Protobuf的代码生成器`protoc`以及相应的源码包。具体资源可从官方下载页面获取,确保版本兼容性以充分发挥其性能优势。此外,配置好开发环境后,可以通过定义`.proto`文件来自动生成Java类,从而简化数据序列化和反序列化的操作,提高通信效率。 ... [详细]
  • Spring – Bean Life Cycle
    Spring – Bean Life Cycle ... [详细]
  • Spring Boot 中配置全局文件上传路径并实现文件上传功能
    本文介绍如何在 Spring Boot 项目中配置全局文件上传路径,并通过读取配置项实现文件上传功能。通过这种方式,可以更好地管理和维护文件路径。 ... [详细]
  • 本文详细介绍了如何使用Python中的smtplib库来发送带有附件的邮件,并提供了完整的代码示例。作者:多测师_王sir,时间:2020年5月20日 17:24,微信:15367499889,公司:上海多测师信息有限公司。 ... [详细]
  • 在Linux系统中避免安装MySQL的简易指南
    在Linux系统中避免安装MySQL的简易指南 ... [详细]
  • 在处理 XML 数据时,如果需要解析 `` 标签的内容,可以采用 Pull 解析方法。Pull 解析是一种高效的 XML 解析方式,适用于流式数据处理。具体实现中,可以通过 Java 的 `XmlPullParser` 或其他类似的库来逐步读取和解析 XML 文档中的 `` 元素。这样不仅能够提高解析效率,还能减少内存占用。本文将详细介绍如何使用 Pull 解析方法来提取 `` 标签的内容,并提供一个示例代码,帮助开发者快速解决问题。 ... [详细]
  • [转]doc,ppt,xls文件格式转PDF格式http:blog.csdn.netlee353086articledetails7920355确实好用。需要注意的是#import ... [详细]
  • 原文网址:https:www.cnblogs.comysoceanp7476379.html目录1、AOP什么?2、需求3、解决办法1:使用静态代理4 ... [详细]
  • 实验九:使用SharedPreferences存储简单数据
    本实验旨在帮助学生理解和掌握使用SharedPreferences存储和读取简单数据的方法,包括程序参数和用户选项。 ... [详细]
  • 深入解析 Lifecycle 的实现原理
    本文将详细介绍 Android Jetpack 中 Lifecycle 组件的实现原理,帮助开发者更好地理解和使用 Lifecycle,避免常见的内存泄漏问题。 ... [详细]
  • 本文介绍了如何利用 `matplotlib` 库中的 `FuncAnimation` 类将 Python 中的动态图像保存为视频文件。通过详细解释 `FuncAnimation` 类的参数和方法,文章提供了多种实用技巧,帮助用户高效地生成高质量的动态图像视频。此外,还探讨了不同视频编码器的选择及其对输出文件质量的影响,为读者提供了全面的技术指导。 ... [详细]
  • 本文介绍了一种自定义的Android圆形进度条视图,支持在进度条上显示数字,并在圆心位置展示文字内容。通过自定义绘图和组件组合的方式实现,详细展示了自定义View的开发流程和关键技术点。示例代码和效果展示将在文章末尾提供。 ... [详细]
  • 在Cisco IOS XR系统中,存在提供服务的服务器和使用这些服务的客户端。本文深入探讨了进程与线程状态转换机制,分析了其在系统性能优化中的关键作用,并提出了改进措施,以提高系统的响应速度和资源利用率。通过详细研究状态转换的各个环节,本文为开发人员和系统管理员提供了实用的指导,旨在提升整体系统效率和稳定性。 ... [详细]
author-avatar
中孝雪瑶诗涵
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有