Netty 自動重連


from: http://www.dozer.cc/2015/05/netty-auto-reconnect.html

 

自動重連

用 Netty 寫 Client 和 Server 的時候必須要去處理自動重連。

Server 端啟動時的錯誤,要去不斷重試。

Client 端不僅要處理啟動時的錯誤,還要處理中途斷開連接。

 

Server 端的處理

和常規的代碼相比,Server 端只要處理一個地方即可:

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,第二部分做真正的監聽端口。

這里最特殊的地方就是在調用bind方法后,添加一個listener檢查是否成功,如果失敗的話,需要調用.channel().eventLoop().schedule()方法,創建一個任務,我這代碼設置的是1秒后嘗試重新連接。

另外考慮到 server 可以被人為關閉,所以還需要檢查當前時候已經關閉。如果不檢查的話,你的 server 可能就永遠也關不掉了。

 

Client 端的處理

client 端啟動流程差不多,但是需要加一個 handler 來處理連接斷開。

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秒后重新連接。

 

示例代碼

大家可以自己跑跑看:

https://github.com/dozer47528/AutoReconnectNettyExample

本作品由  Dozer 創作,采用  知識共享署名-非商業性使用 4.0 國際許可協議 進行許可。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM