from: http://www.dozer.cc/2015/05/netty-auto-reconnect.htmlhtml
用 Netty 寫 Client 和 Server 的時候必需要去處理自動重連。java
Server 端啓動時的錯誤,要去不斷重試。git
Client 端不只要處理啓動時的錯誤,還要處理中途斷開鏈接。github
和常規的代碼相比,Server 端只要處理一個地方便可:bootstrap
public final class TcpServer { private volatile EventLoopGroup bossGroup; private volatile EventLoopGroup workerGroup; private volatile ServerBootstrap bootstrap; private volatile boolean closed = false; private final int localPort; public TcpServer(int localPort) { this.localPort = localPort; } public void close() { closed = true; bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); System.out.println("Stopped Tcp Server: " + localPort); } public void init() { closed = false; bossGroup = new NioEventLoopGroup(); workerGroup = new NioEventLoopGroup(); bootstrap = new ServerBootstrap(); bootstrap.group(bossGroup, workerGroup); bootstrap.channel(NioServerSocketChannel.class); bootstrap.childHandler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) throws Exception { //todo: add more handler } }); doBind(); } protected void doBind() { if (closed) { return; } bootstrap.bind(localPort).addListener(new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture f) throws Exception { if (f.isSuccess()) { System.out.println("Started Tcp Server: " + localPort); } else { System.out.println("Started Tcp Server Failed: " + localPort); f.channel().eventLoop().schedule(() -> doBind(), 1, TimeUnit.SECONDS); } } }); } }
咱們把整個初始化分紅了兩個部分,第一部分是初始化相關 class,第二部分作真正的監聽端口。ide
這裏最特殊的地方就是在調用bind
方法後,添加一個listener
檢查是否成功,若是失敗的話,須要調用.channel().eventLoop().schedule()
方法,建立一個任務,我這代碼設置的是1秒後嘗試從新鏈接。oop
另外考慮到 server 能夠被人爲關閉,因此還須要檢查當前時候已經關閉。若是不檢查的話,你的 server 可能就永遠也關不掉了。this
client 端啓動流程差很少,可是須要加一個 handler 來處理鏈接斷開。spa
public class TcpClient { private volatile EventLoopGroup workerGroup; private volatile Bootstrap bootstrap; private volatile boolean closed = false; private final String remoteHost; private final int remotePort; public TcpClient(String remoteHost, int remotePort) { this.remoteHost = remoteHost; this.remotePort = remotePort; } public void close() { closed = true; workerGroup.shutdownGracefully(); System.out.println("Stopped Tcp Client: " + getServerInfo()); } public void init() { closed = false; workerGroup = new NioEventLoopGroup(); bootstrap = new Bootstrap(); bootstrap.group(workerGroup); bootstrap.channel(NioSocketChannel.class); bootstrap.handler(new ChannelInitializer<SocketChannel>() { @Override public void initChannel(SocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); pipeline.addFirst(new ChannelInboundHandlerAdapter() { @Override public void channelInactive(ChannelHandlerContext ctx) throws Exception { super.channelInactive(ctx); ctx.channel().eventLoop().schedule(() -> doConnect(), 1, TimeUnit.SECONDS); } }); //todo: add more handler } }); doConnect(); } private void doConnect() { if (closed) { return; } ChannelFuture future = bootstrap.connect(new InetSocketAddress(remoteHost, remotePort)); future.addListener(new ChannelFutureListener() { public void operationComplete(ChannelFuture f) throws Exception { if (f.isSuccess()) { System.out.println("Started Tcp Client: " + getServerInfo()); } else { System.out.println("Started Tcp Client Failed: " + getServerInfo()); f.channel().eventLoop().schedule(() -> doConnect(), 1, TimeUnit.SECONDS); } } }); } private String getServerInfo() { return String.format("RemoteHost=%s RemotePort=%d", remotePort, remotePort); } }
能夠看到,咱們在channelInactive
事件中,也建立了一個任務,在1秒後從新鏈接。netty
你們能夠本身跑跑看:
https://github.com/dozer47528/AutoReconnectNettyExample