Netty客户端连接服务端失败及断开与客户端连接时尝试重连

版权声明:版权声明:本文为博主原创文章,转载请标明出处! https://blog.csdn.net/qq_35457078/article/details/85317684

Netty客户端重连机制

场景:
 1.Netty初次启动客户端,如果无法连接到服务端,将尝试重连。
 2.在客户端与服务端保持长连接的过程中,如果连接断开,尝试与服务端重连。

  1. 主要代码

     Netty客户端启动处理类

    @Service("nettyClient")
    public class NettyClient {
    	private final static Logger log = LoggerFactory.getLogger(NettyClient.class);
    	private EventLoopGroup loop = new NioEventLoopGroup();
    
    	@Autowired
    	private NettyFilter nettyFilter;
    
    	@Autowired
    	private AppConfig appConfig;
    
    	/**
    	 * 重连标志
    	 */
    	public static boolean retryConnectFlag = false;
    
    	public void run() {
    
    		doConnect(new Bootstrap(), loop);
    	}
    
    	/**
    	 * netty client 连接,连接失败10秒后重试连接
    	 */
    	public void doConnect(Bootstrap bootstrap, EventLoopGroup eventLoopGroup) {
    		ChannelFuture f = null;
    		try {
    			if (bootstrap != null) {
    				bootstrap.group(eventLoopGroup);
    				bootstrap.channel(NioSocketChannel.class);
    				bootstrap.option(ChannelOption.SO_KEEPALIVE, true);
    				bootstrap.handler(nettyFilter);
    				bootstrap.remoteAddress(appConfig.getHost(), appConfig.getPort());
    				bootstrap.connect().addListener(new ChannelFutureListener() {
    					
    					@Override
    					public void operationComplete(ChannelFuture future) throws Exception {
    						// TODO Auto-generated method stub
    						
    					}
    				});
    				// 	Cache.channel为缓存的与服务端的连接channel,在其他发送消息的时候使用。
    				Cache.channel = bootstrap.connect().addListener((ChannelFuture futureListener) -> {
    					final EventLoop eventLoop = futureListener.channel().eventLoop();
    					if (!futureListener.isSuccess()) {
    						log.warn("客户端与服务端建立连接失败,10s之后尝试重连...");
    						eventLoop.schedule(() -> doConnect(new Bootstrap(), eventLoop), 10, TimeUnit.SECONDS);
    					} else {
    						if (retryConnectFlag) {
    							// 如果连接成功后,再次断开,则尝试重连。
    							retryConnectFlag = false;
    							log.info("客户端重连成功,port:{}", appConfig.getPort());
    						} else {
    						   // 客户端首次成功连接服务端后,这里有个验证登录服务端的动作(不要验证可以取消)
    							log.info("客户端与服务器连接成功,port:{},开始登录服务端...", appConfig.getPort());
    						}
    					}
    				}).channel();
    			}
    		} catch (Exception e) {
    			log.error("连接客户端失败,失败信息:" + e);
    		}finally {
    			// 要实现重连,所以不能关闭loop
    			//loop.shutdownGracefully();
    		}
    	}
    }
    

     客户端与服务端心跳处理类,与客户端断开连接后的重试代码在channelInactive()这个方法中

    @Service("idleclienthandler")
    @ChannelHandler.Sharable
    public class IdleClientHandler extends SimpleChannelInboundHandler<MessageBase> {
    	private final static Logger logger = LoggerFactory.getLogger(IdleClientHandler.class);
    	private long heartbeatCount = 0;
    	
    	@Autowired
    	private NettyClient nettyClient;
    
    
    	@Override
    	public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
    		if (evt instanceof IdleStateEvent) {
    			IdleStateEvent event = (IdleStateEvent) evt;
    		 	logger.info(ctx.channel().remoteAddress() + ",超时类型:" + event.state());
    			sendPingMsg(ctx);
    		} else {
    			super.userEventTriggered(ctx, evt);
    		}
    	}
    
    	/**
    	 * 发送ping消息
    	 * @param context
    	 */
    	protected void sendPingMsg(ChannelHandlerContext context) {
    		MessageBase body = NettyMessage.MessageBase.newBuilder()
    				.setCmd(CommandType.PING)
    				.setPtcode(Cache.ptcode)
    				.setData("ping")
    				.build();
    		context.writeAndFlush(body);
    		heartbeatCount++;
    		logger.info("Client sent ping msg to " + context.channel().remoteAddress() + ", count: " + heartbeatCount);
    	}
    
    	/**
    	 * 处理断开重连
    	 */
    	@SuppressWarnings("static-access")
    	@Override
    	public void channelInactive(ChannelHandlerContext ctx) throws Exception {
    		logger.info("与服务器连接断开,尝试重新连接...");
    		nettyClient.retryConnectFlag = true;
    		final EventLoop eventLoop = ctx.channel().eventLoop();  
    	    nettyClient.doConnect(new Bootstrap(), eventLoop);  
    		super.channelInactive(ctx);  
    	}
    
    	@Override
    	protected void channelRead0(ChannelHandlerContext ctx, MessageBase msg) throws Exception {
    		logger.info("收到的消息!{}",msg);
    	}
    }
    

猜你喜欢

转载自blog.csdn.net/qq_35457078/article/details/85317684