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