@Override public void run() { EventLoopGroup workerGroup = new NioEventLoopGroup(); try { Bootstrap b = new Bootstrap(); b.group(workerGroup); b.channel(NioSocketChannel.class); b.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, client.getSettings().connectTimeout()); b.option(ChannelOption.SO_KEEPALIVE, true); b.handler(new ChannelInitializer() { @Override public void initChannel(SocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); pipeline.addLast(clientHandler); } }); ChannelFuture f = b.connect(remoteAddress, new InetSocketAddress(InetAddress.getLocalHost().getHostAddress(), getLocalPort())).awaitUninterruptibly(); f.addListener((ChannelFutureListener) future -> { if (future.isSuccess()) { logger.info("Connected to: [" + remoteAddress.getAddress().getHostAddress() + ":" + remoteAddress.getPort() + "]"); packetHandler.getClient().setConnected(true); client.getEventListener().onConnect(client); writeMessage(UnconnectedPing.create(System.currentTimeMillis(), packetHandler.getClient().getClientId())); } else { logger.error("Error connecting to: [" + remoteAddress.getAddress().getHostAddress() + ":" + remoteAddress.getPort() + "]", future.cause()); client.getEventListener().onException(client, future.cause()); } }); f.channel().closeFuture().awaitUninterruptibly(); } catch (Exception e) { logger.error("Error connecting to: [" + remoteAddress.getAddress().getHostAddress() + ":" + remoteAddress.getPort() + "]", e); client.getEventListener().onException(client, e); } finally { workerGroup.shutdownGracefully(); } }