断线重接更好用的 *** netty断线重连原理( 二 )


TcpClient —— TCP贯穿的存户端
public class TcpClient { private String host; private int port; private Bootstrap bootstrap; /** 将<code>Channel</code>生存起来, 可用来在其余非handler的场合发送数据 */ private Channel channel; public TcpClient(String host, int port) { this(host, port, new ExponentialBackOffRetry(1000, Integer.MAX_VALUE, 60 * 1000)); } public TcpClient(String host, int port, RetryPolicy retryPolicy) { this.host = host; this.port = port; init(); } /** * 向长途TCP效劳器乞求贯穿 */ public void connect() { synchronized (bootstrap) { ChannelFuture future = bootstrap.connect(host, port); this.channel = future.channel(); } } private void init() { EventLoopGroup group = new NioEventLoopGroup(); // bootstrap 可重用, 只需在TcpClient范例化的功夫初始化即可. bootstrap = new Bootstrap(); bootstrap.group(group) .channel(NioSocketChannel.class) .handler(new ClientHandlersInitializer(TcpClient.this)); } public static void main(String[] args) { TcpClient tcpClient = new TcpClient("localhost", 2222); tcpClient.connect(); }}Server端
ServerIdleStateTrigger —— 断连触发器
/** * <p>在规则功夫内未收到存户端的任何数据包, 将积极割断该贯穿</p> */public class ServerIdleStateTrigger 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) { // 在规则功夫内没有收到存户端的下行数据, 积极割断贯穿 ctx.disconnect(); } } else { super.userEventTriggered(ctx, evt); } }}ServerBizHandler —— 效劳器端的交易处置器
/** * <p>收到来自存户端的数据包后, 径直在遏制台打字与印刷出来.</p> */@ChannelHandler.Sharablepublic class ServerBizHandler extends SimpleChannelInboundHandler<String> { private final String REC_HEART_BEAT = "I had received the heart beat!"; @Override protected void channelRead0(ChannelHandlerContext ctx, String data) throws Exception { try { System.out.println("receive data: " + data);// ctx.writeAndFlush(REC_HEART_BEAT); } catch (Exception e) { e.printStackTrace(); } } @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { System.out.println("Established connection with the remote client."); // do something ctx.fireChannelActive(); } @Override public void channelInactive(ChannelHandlerContext ctx) throws Exception { System.out.println("Disconnected with the remote client."); // do something ctx.fireChannelInactive(); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { cause.printStackTrace(); ctx.close(); }}ServerHandlerInitializer —— 效劳器端处置器汇合的初始化类
/** * <p>用来初始化效劳器端波及到的一切<code>Handler</code></p> */public class ServerHandlerInitializer extends ChannelInitializer<SocketChannel> { protected void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast("idleStateHandler", new IdleStateHandler(5, 0, 0)); ch.pipeline().addLast("idleStateTrigger", new ServerIdleStateTrigger()); ch.pipeline().addLast("frameDecoder", new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 4, 0, 4)); ch.pipeline().addLast("frameEncoder", new LengthFieldPrepender(4)); ch.pipeline().addLast("decoder", new StringDecoder()); ch.pipeline().addLast("encoder", new StringEncoder()); ch.pipeline().addLast("bizHandler", new ServerBizHandler()); }}注:new IdleStateHandler(5, 0, 0)该handler代办即使在5秒内没有收到来自存户端的任何数据包(囊括但不限于心跳包),将会积极割断与该存户端的贯穿 。
TcpServer —— 效劳器端
public class TcpServer { private int port; private ServerHandlerInitializer serverHandlerInitializer; public TcpServer(int port) { this.port = port; this.serverHandlerInitializer = new ServerHandlerInitializer(); } public void start() { EventLoopGroup bossGroup = new NioEventLoopGroup(1); EventLoopGroup workerGroup = new NioEventLoopGroup(); try { ServerBootstrap bootstrap = new ServerBootstrap(); bootstrap.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) .childHandler(this.serverHandlerInitializer); // 绑定端口,发端接受进入的贯穿 ChannelFuture future = bootstrap.bind(port).sync(); System.out.println("Server start listen at " + port); future.channel().closeFuture().sync(); } catch (Exception e) { bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); e.printStackTrace(); } } public static void main(String[] args) throws Exception { int port = 2222; new TcpServer(port).start(); }}至此,一切代码仍旧编写结束 。
尝试
开始启用存户端,再启用效劳器端 。启用实行后,在存户端的遏制台上,不妨看到打字与印刷如次一致日记:
存户端遏制台输入的日记
在效劳器端不妨看到遏制台输入了一致如次的日记:

推荐阅读