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


public class ClientHandlersInitializer extends ChannelInitializer<SocketChannel> { private ReconnectHandler reconnectHandler; private EchoHandler echoHandler; public ClientHandlersInitializer(TcpClient tcpClient) { Assert.notNull(tcpClient, "TcpClient can not be null."); this.reconnectHandler = new ReconnectHandler(tcpClient); this.echoHandler = new EchoHandler(); } @Override protected void initChannel(SocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); pipeline.addLast(this.reconnectHandler); pipeline.addLast(new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 4, 0, 4)); pipeline.addLast(new LengthFieldPrepender(4)); pipeline.addLast(new StringDecoder(CharsetUtil.UTF_8)); pipeline.addLast(new StringEncoder(CharsetUtil.UTF_8)); pipeline.addLast(new Pinger()); }}TcpClient
在之前的普通上增添重连、重连战略的扶助 。
public class TcpClient { private String host; private int port; private Bootstrap bootstrap; /** 重连战略 */ private RetryPolicy retryPolicy; /** 将<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; this.retryPolicy = retryPolicy; init(); } /** * 向长途TCP效劳器乞求贯穿 */ public void connect() { synchronized (bootstrap) { ChannelFuture future = bootstrap.connect(host, port); future.addListener(getConnectionListener()); this.channel = future.channel(); } } public RetryPolicy getRetryPolicy() { return retryPolicy; } private void init() { EventLoopGroup group = new NioEventLoopGroup(); // bootstrap 可重用, 只需在TcpClient范例化的功夫初始化即可. bootstrap = new Bootstrap(); bootstrap.group(group) .channel(NioSocketChannel.class) .handler(new ClientHandlersInitializer(TcpClient.this)); } private ChannelFutureListener getConnectionListener() { return new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture future) throws Exception { if (!future.isSuccess()) { future.channel().pipeline().fireChannelInactive(); } } }; } public static void main(String[] args) { TcpClient tcpClient = new TcpClient("localhost", 2222); tcpClient.connect(); }}尝试
在尝试之前,为了避开 Connection reset by peer 特殊,不妨略微窜改Pinger的ping()本领,增添if (second == 5)的前提确定 。如次:
private void ping(Channel channel) { int second = Math.max(1, random.nextInt(baseRandom)); if (second == 5) { second = 6; } System.out.println("next heart beat will send after " + second + "s."); ScheduledFuture<?> future = channel.eventLoop().schedule(new Runnable() { @Override public void run() { if (channel.isActive()) { System.out.println("sending heart beat to the server..."); channel.writeAndFlush(ClientIdleStateTrigger.HEART_BEAT); } else { System.err.println("The connection had broken, cancel the task that will send a heart beat."); channel.closeFuture(); throw new RuntimeException(); } } }, second, TimeUnit.SECONDS); future.addListener(new GenericFutureListener() { @Override public void operationComplete(Future future) throws Exception { if (future.isSuccess()) { ping(channel); } } }); }启用存户端
先只启用存户端,查看遏制台输入,不妨看到一致如次日记:
断线重连尝试——存户端遏制台输入
不妨看到,当存户端创造没辙贯穿到效劳器端,以是从来试验重连 。跟着重试度数减少,重试功夫间隙越大,但又不想无穷增大下来,以是须要定一个阈值,比方60s 。如上海图书馆所示,当下一次重试功夫胜过60s时,会打字与印刷Sleep extension too large(*). Pinning to 60000,单元为ms 。展示这句话的道理是,计划出来的功夫胜过阈值(60s),以是把真实安置的功夫重置为阈值(60s) 。
启用效劳器端
接着启用效劳器端,而后连接查看存户端遏制台输入 。
断线重连尝试——效劳器端启用后存户端遏制台输入
【断线重接更好用的 ***netty断线重连原理】不妨看到,在第9次重试波折后,第10次重试之前,启用的效劳器,以是第10次重连的截止为Successfully established a connection to the server.,即胜利贯穿到效劳器 。接下来由于仍旧大概时ping效劳器,以是展示断线重连、断线重连的轮回 。

推荐阅读