### Question:
NettyRemotingClient { public void sendAsync(final Host host, final Command command, final long timeoutMillis, final InvokeCallback invokeCallback) throws InterruptedException, RemotingException { final Channel channel = getChannel(host); if (channel == null) { throw new RemotingException("network error"); } final long opaque = command.getOpaque(); boolean acquired = this.asyncSemaphore.tryAcquire(timeoutMillis, TimeUnit.MILLISECONDS); if (acquired) { final ReleaseSemaphore releaseSemaphore = new ReleaseSemaphore(this.asyncSemaphore); final ResponseFuture responseFuture = new ResponseFuture(opaque, timeoutMillis, invokeCallback, releaseSemaphore); try { channel.writeAndFlush(command).addListener(new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture future) throws Exception { if (future.isSuccess()) { responseFuture.setSendOk(true); return; } else { responseFuture.setSendOk(false); } responseFuture.setCause(future.cause()); responseFuture.putResponse(null); try { responseFuture.executeInvokeCallback(); } catch (Throwable ex) { logger.error("execute callback error", ex); } finally { responseFuture.release(); } } }); } catch (Throwable ex) { responseFuture.release(); throw new RemotingException(String.format("send command to host: %s failed", host), ex); } } else { String message = String.format("try to acquire async semaphore timeout: %d, waiting thread num: %d, total permits: %d", timeoutMillis, asyncSemaphore.getQueueLength(), asyncSemaphore.availablePermits()); throw new RemotingTooMuchRequestException(message); } } NettyRemotingClient(final NettyClientConfig clientConfig); void sendAsync(final Host host, final Command command,
                          final long timeoutMillis,
                          final InvokeCallback invokeCallback); Command sendSync(final Host host, final Command command, final long timeoutMillis); void send(final Host host, final Command command); void registerProcessor(final CommandType commandType, final NettyRequestProcessor processor); void registerProcessor(final CommandType commandType, final NettyRequestProcessor processor, final ExecutorService executor); Channel getChannel(Host host); Channel createChannel(Host host, boolean isSync); void close(); void closeChannel(Host host);  }### Answer:
@Test public void testSendAsync(){ NettyServerConfig serverConfig = new NettyServerConfig(); NettyRemotingServer server = new NettyRemotingServer(serverConfig); server.registerProcessor(CommandType.PING, new NettyRequestProcessor() { @Override public void process(Channel channel, Command command) { channel.writeAndFlush(Pong.create(command.getOpaque())); } }); server.start(); final NettyClientConfig clientConfig = new NettyClientConfig(); NettyRemotingClient client = new NettyRemotingClient(clientConfig); CountDownLatch latch = new CountDownLatch(1); Command commandPing = Ping.create(); try { final AtomicLong opaque = new AtomicLong(0); client.sendAsync(new Host("127.0.0.1", serverConfig.getListenPort()), commandPing, 2000, new InvokeCallback() { @Override public void operationComplete(ResponseFuture responseFuture) { opaque.set(responseFuture.getOpaque()); latch.countDown(); } }); latch.await(); Assert.assertEquals(commandPing.getOpaque(), opaque.get()); } catch (Exception e) { e.printStackTrace(); } server.close(); client.close(); }