分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow
也欢迎大家转载本篇文章。分享知识,造福人民,实现我们中华民族伟大复兴!
sigh,写这篇博客的时候老脸还是红了一下,心里还是有些唏嘘的,应该算是剽窃吧,每个人的代码功力的确是有差距的,好在文章的标题是“一起学”,而不是开涛大神的“跟我学”系列的文章,我们还是多花点时间学习吧,感叹无用~
最近工作比较忙,但闲暇之余还是看了阿里的冯家春(fengjiachun)的github上的开源代码Jupiter,写的RPC框架让我感叹人外有人,废话不多说,下面的代码全部截取自Jupiter,写了一个比较完整的例子,供大家一起学习分享,再次对@Luca抱拳,Jupiter的Github地址:
https://github.com/fengjiachun/Jupiter
今天研究的是,心跳和重连,虽然这次是大神写的代码,但是万变不离其宗,我们先回顾一下Netty应用心跳和重连的整个过程:
1)客户端连接服务端
2)在客户端的的ChannelPipeline中加入一个比较特殊的IdleStateHandler,设置一下客户端的写空闲时间,例如5s
3)当客户端的所有ChannelHandler中4s内没有write事件,则会触发userEventTriggered方法(上文介绍过)
4)我们在客户端的userEventTriggered中对应的触发事件下发送一个心跳包给服务端,检测服务端是否还存活,防止服务端已经宕机,客户端还不知道
5)同样,服务端要对心跳包做出响应,其实给客户端最好的回复就是“不回复”,这样可以服务端的压力,假如有10w个空闲Idle的连接,那么服务端光发送心跳回复,则也是费事的事情,那么怎么才能告诉客户端它还活着呢,其实很简单,因为5s服务端都会收到来自客户端的心跳信息,那么如果10秒内收不到,服务端可以认为客户端挂了,可以close链路
6)加入服务端因为什么因素导致宕机的话,就会关闭所有的链路链接,所以作为客户端要做的事情就是短线重连
以上描述的就是整个心跳和重连的整个过程,虽然很简单,上一篇blog也写了一个Demo,简单地做了一下上述功能
要写工业级的Netty心跳重连的代码,需要解决一下几个问题:
1)ChannelPipeline中的ChannelHandlers的维护,首次连接和重连都需要对ChannelHandlers进行管理
2)重连对象的管理,也就是bootstrap对象的管理
3)重连机制编写
完整的代码:https://github.com/BazingaLyn/netty-study/tree/master/src/main/java/com/lyncc/netty/idle
下面我们就看大神是如何解决这些问题的,首先先定义一个接口ChannelHandlerHolder,用来保管ChannelPipeline中的Handlers的
- package com.lyncc.netty.idle;
- import io.netty.channel.ChannelHandler;
- /**
- *
- * 客户端的ChannelHandler集合,由子类实现,这样做的好处:
- * 继承这个接口的所有子类可以很方便地获取ChannelPipeline中的Handlers
- * 获取到handlers之后方便ChannelPipeline中的handler的初始化和在重连的时候也能很方便
- * 地获取所有的handlers
- */
- public interface ChannelHandlerHolder {
- ChannelHandler[] handlers();
- }
HeartBeatServer.java
- package com.lyncc.netty.idle;
- import io.netty.bootstrap.ServerBootstrap;
- import io.netty.channel.ChannelFuture;
- import io.netty.channel.ChannelInitializer;
- import io.netty.channel.ChannelOption;
- import io.netty.channel.EventLoopGroup;
- import io.netty.channel.nio.NioEventLoopGroup;
- import io.netty.channel.socket.SocketChannel;
- import io.netty.channel.socket.nio.NioServerSocketChannel;
- import io.netty.handler.codec.string.StringDecoder;
- import io.netty.handler.codec.string.StringEncoder;
- import io.netty.handler.logging.LogLevel;
- import io.netty.handler.logging.LoggingHandler;
- import io.netty.handler.timeout.IdleStateHandler;
- import java.net.InetSocketAddress;
- import java.util.concurrent.TimeUnit;
- public class HeartBeatServer {
- private final AcceptorIdleStateTrigger idleStateTrigger = new AcceptorIdleStateTrigger();
- private int port;
- public HeartBeatServer(int port) {
- this.port = port;
- }
- public void start() {
- EventLoopGroup bossGroup = new NioEventLoopGroup(1);
- EventLoopGroup workerGroup = new NioEventLoopGroup();
- try {
- ServerBootstrap sbs = new ServerBootstrap().group(bossGroup, workerGroup)
- .channel(NioServerSocketChannel.class).handler(new LoggingHandler(LogLevel.INFO))
- .localAddress(new InetSocketAddress(port)).childHandler(new ChannelInitializer<SocketChannel>() {
- protected void initChannel(SocketChannel ch) throws Exception {
- ch.pipeline().addLast(new IdleStateHandler(5, 0, 0, TimeUnit.SECONDS));
- ch.pipeline().addLast(idleStateTrigger);
- ch.pipeline().addLast("decoder", new StringDecoder());
- ch.pipeline().addLast("encoder", new StringEncoder());
- ch.pipeline().addLast(new HeartBeatServerHandler());
- };
- }).option(ChannelOption.SO_BACKLOG, 128).childOption(ChannelOption.SO_KEEPALIVE, true);
- // 绑定端口,开始接收进来的连接
- ChannelFuture future = sbs.bind(port).sync();
- System.out.println("Server start listen at " + port);
- future.channel().closeFuture().sync();
- } catch (Exception e) {
- bossGroup.shutdownGracefully();
- workerGroup.shutdownGracefully();
- }
- }
- public static void main(String[] args) throws Exception {
- int port;
- if (args.length > 0) {
- port = Integer.parseInt(args[0]);
- } else {
- port = 8080;
- }
- new HeartBeatServer(port).start();
- }
- }
- package com.lyncc.netty.idle;
- import io.netty.channel.ChannelHandler;
- import io.netty.channel.ChannelHandlerContext;
- import io.netty.channel.ChannelInboundHandlerAdapter;
- import io.netty.handler.timeout.IdleState;
- import io.netty.handler.timeout.IdleStateEvent;
- @ChannelHandler.Sharable
- public class AcceptorIdleStateTrigger extends ChannelInboundHandlerAdapter {
- @Override
- public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
- if (evt instanceof IdleStateEvent) {
- IdleState state = ((IdleStateEvent) evt).state();
- if (state == IdleState.READER_IDLE) {
- throw new Exception("idle exception");