@Override
 public void channelRead(final ChannelHandlerContext ctx, final Object msg) throws Exception {
   final ZMTPMessage message = (ZMTPMessage) msg;
   meter.inc();
   message.release();
   ctx.write(req());
   flusher.flush();
 }
  private static class ClientHandler extends ChannelInboundHandlerAdapter {

    private static final int CONCURRENCY = 1000;

    private static final ZMTPMessage REQUEST =
        ZMTPMessage.fromUTF8(
            "envelope1",
            "envelope2",
            "",
            Strings.repeat("d", 20),
            Strings.repeat("d", 40),
            Strings.repeat("d", 100));

    private final ProgressMeter meter;

    private BatchFlusher flusher;

    public ClientHandler(final ProgressMeter meter) {
      this.meter = meter;
    }

    @Override
    public void channelRegistered(final ChannelHandlerContext ctx) throws Exception {
      this.flusher = new BatchFlusher(ctx.channel());
    }

    @Override
    public void userEventTriggered(final ChannelHandlerContext ctx, final Object evt)
        throws Exception {
      if (evt instanceof ZMTPHandshakeSuccess) {
        for (int i = 0; i < CONCURRENCY; i++) {
          ctx.write(req());
        }
        flusher.flush();
      }
    }

    private ZMTPMessage req() {
      return REQUEST.retain();
    }

    @Override
    public void channelRead(final ChannelHandlerContext ctx, final Object msg) throws Exception {
      final ZMTPMessage message = (ZMTPMessage) msg;
      meter.inc();
      message.release();
      ctx.write(req());
      flusher.flush();
    }
  }
 private ZMTPMessage req() {
   return REQUEST.retain();
 }