斷線重接更好用的 *** 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效勞器,以是展示斷線重連、斷線重連的輪回 。

推薦閱讀