[
  {
    "path": "README.md",
    "content": "# netty-study\n\nnetty4.x知识点学习\n\n\n\n### 1) [生产级别的心跳重连](https://github.com/BazingaLyn/netty-study/tree/master/src/main/java/com/lyncc/netty/idle)\n\n### 2) [比较规范的netty的C/S端编写](https://github.com/BazingaLyn/netty-study/tree/master/src/main/java/com/lyncc/netty/production)\n\n   1)有心跳机制\n   \n   2)有ACK检验机制\n   \n   3)有重连机制\n   \n   4)自定义交互协议\n   \n   (代码是从Jupiter和RocketMQ中截出)\n"
  },
  {
    "path": "pom.xml",
    "content": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<groupId>com.study</groupId>\n\t<artifactId>netty-study</artifactId>\n\t<version>0.0.1-SNAPSHOT</version>\n\t<packaging>jar</packaging>\n\n\t<name>netty-study</name>\n\t<url>http://maven.apache.org</url>\n\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<version.jackson.core>2.6.3</version.jackson.core>\n\t\t<slf4j.version>1.7.5</slf4j.version>\n\t</properties>\n\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>junit</groupId>\n\t\t\t<artifactId>junit</artifactId>\n\t\t\t<version>4.10</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.slf4j</groupId>\n\t\t\t<artifactId>slf4j-api</artifactId>\n\t\t\t<version>${slf4j.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>io.netty</groupId>\n\t\t\t<artifactId>netty-all</artifactId>\n\t\t\t<version>4.0.21.Final</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.fasterxml.jackson.core</groupId>\n\t\t\t<artifactId>jackson-core</artifactId>\n\t\t\t<version>${version.jackson.core}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.fasterxml.jackson.core</groupId>\n\t\t\t<artifactId>jackson-databind</artifactId>\n\t\t\t<version>${version.jackson.core}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.google.protobuf</groupId>\n\t\t\t<artifactId>protobuf-java</artifactId>\n\t\t\t<version>2.6.1</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>io.protostuff</groupId>\n\t\t\t<artifactId>protostuff-core</artifactId>\n\t\t\t<version>1.3.5</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>io.protostuff</groupId>\n\t\t\t<artifactId>protostuff-runtime</artifactId>\n\t\t\t<version>1.3.5</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.objenesis</groupId>\n\t\t\t<artifactId>objenesis</artifactId>\n\t\t\t<version>2.1</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>ch.qos.logback</groupId>\n\t\t\t<artifactId>logback-classic</artifactId>\n\t\t\t<version>1.0.13</version>\n\t\t</dependency>\n\t</dependencies>\n</project>\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/attributeMap/AttributeMapConstant.java",
    "content": "package com.lyncc.netty.attributeMap;\n\nimport io.netty.util.AttributeKey;\n\npublic class AttributeMapConstant {\n    \n    public static final AttributeKey<NettyChannel> NETTY_CHANNEL_KEY = AttributeKey.valueOf(\"netty.channel\");\n\n}\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/attributeMap/HelloWorld2ClientHandler.java",
    "content": "package com.lyncc.netty.attributeMap;\n\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.channel.ChannelInboundHandlerAdapter;\nimport io.netty.util.Attribute;\nimport io.netty.util.AttributeKey;\n\nimport java.util.HashSet;\n\npublic class HelloWorld2ClientHandler extends ChannelInboundHandlerAdapter {\n\n    public static final AttributeKey<HashSet<Integer>> NETTY_CHANNEL_KEY1 = AttributeKey.valueOf(\"netty.channel1\");\n    \n    @Override\n    public void channelActive(ChannelHandlerContext ctx) {\n        Attribute<HashSet<Integer>> attr = ctx.channel().attr(NETTY_CHANNEL_KEY1);\n        HashSet<Integer> sets = attr.get();\n        if (sets == null) {\n            HashSet<Integer> newSet = new HashSet<Integer>();\n            sets = attr.setIfAbsent(newSet);\n            if(null == sets){\n                System.out.println(\"GGGGGGGGGGGGGGGGGGGGGG NULLLLLLLLLLL\");\n                sets = newSet;\n            }\n            HashSet<Integer> sets2 = attr.get();\n            System.out.println(\"RRRRRRRRRRRRRRRRR ===\"+sets2.size());\n            for(Integer i :sets2){\n                System.out.println(\"value is GGGGGGGGGGG====\"+i);\n            }\n            \n        } \n        sets.add(1);\n        HashSet<Integer> sets3 = attr.get();\n        System.out.println(\"RRRRRRRRRRRRRRRRR2 ===\"+sets3.size());\n        System.out.println(\"HelloWorldC2ientHandler Active\");\n        ctx.fireChannelActive();\n    }\n    \n    \n    public static void main(String[] args) {\n         Student student = new Student(\"1\", 21);\n         Student s =student;\n         \n         s.setAge(88);\n         System.out.println(student.getAge());\n        \n    }\n    \n     static class Student {\n       String id;\n       int age;\n    public String getId() {\n        return id;\n    }\n    public void setId(String id) {\n        this.id = id;\n    }\n    public int getAge() {\n        return age;\n    }\n    public void setAge(int age) {\n        this.age = age;\n    }\n    public Student(String id, int age) {\n        super();\n        this.id = id;\n        this.age = age;\n    }\n       \n    }\n\n    @Override\n    public void channelRead(ChannelHandlerContext ctx, Object msg) {\n        Attribute<HashSet<Integer>> attr = ctx.channel().attr(NETTY_CHANNEL_KEY1);\n        HashSet<Integer> sets = attr.get();\n        if (sets == null) {\n           System.out.println(\"没有值啊\");\n        }else{\n            for(Integer i :sets){\n                System.out.println(\"value is ====\"+i);\n            }\n        }\n        System.out.println(\"HelloWorldClientHandler read Message:\" + msg);\n    }\n\n    @Override\n    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {\n        cause.printStackTrace();\n        ctx.close();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/attributeMap/HelloWorldClient.java",
    "content": "package com.lyncc.netty.attributeMap;\n\nimport io.netty.bootstrap.Bootstrap;\nimport io.netty.channel.ChannelFuture;\nimport io.netty.channel.ChannelInitializer;\nimport io.netty.channel.ChannelOption;\nimport io.netty.channel.ChannelPipeline;\nimport io.netty.channel.EventLoopGroup;\nimport io.netty.channel.nio.NioEventLoopGroup;\nimport io.netty.channel.socket.SocketChannel;\nimport io.netty.channel.socket.nio.NioSocketChannel;\nimport io.netty.handler.codec.string.StringDecoder;\nimport io.netty.handler.codec.string.StringEncoder;\n\npublic class HelloWorldClient {\n    \n    static final String HOST = System.getProperty(\"host\", \"127.0.0.1\");\n    static final int PORT = Integer.parseInt(System.getProperty(\"port\", \"8080\"));\n    static final int SIZE = Integer.parseInt(System.getProperty(\"size\", \"256\"));\n\n    public static void main(String[] args) throws Exception {\n        initChannel();\n    }\n    \n    public static void initChannel() throws InterruptedException{\n        // Configure the client.\n        EventLoopGroup group = new NioEventLoopGroup();\n        try {\n            Bootstrap b = new Bootstrap();\n            b.group(group)\n             .channel(NioSocketChannel.class)\n             .option(ChannelOption.TCP_NODELAY, true)\n             .handler(new ChannelInitializer<SocketChannel>() {\n                 @Override\n                 public void initChannel(SocketChannel ch) throws Exception {\n                     ChannelPipeline p = ch.pipeline();\n                     p.addLast(\"decoder\", new StringDecoder());\n                     p.addLast(\"encoder\", new StringEncoder());\n                     p.addLast(new HelloWorldClientHandler());\n                     p.addLast(new HelloWorld2ClientHandler());\n                 }\n             });\n\n            ChannelFuture future = b.connect(HOST, PORT).sync();\n            future.channel().writeAndFlush(\"hello Netty,Test attributeMap\");\n            future.channel().closeFuture().sync();\n        } finally {\n            group.shutdownGracefully();\n        }\n    \n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/attributeMap/HelloWorldClientHandler.java",
    "content": "package com.lyncc.netty.attributeMap;\n\nimport static com.lyncc.netty.attributeMap.AttributeMapConstant.NETTY_CHANNEL_KEY;\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.channel.ChannelInboundHandlerAdapter;\nimport io.netty.util.Attribute;\n\nimport java.util.Date;\npublic class HelloWorldClientHandler extends ChannelInboundHandlerAdapter {\n\n\n    @Override\n    public void channelActive(ChannelHandlerContext ctx) {\n        Attribute<NettyChannel> attr = ctx.channel().attr(NETTY_CHANNEL_KEY);\n        NettyChannel nChannel = attr.get();\n        if (nChannel == null) {\n            NettyChannel newNChannel = new NettyChannel(\"HelloWorld0Client\", new Date());\n            nChannel = attr.setIfAbsent(newNChannel);\n        } else {\n            System.out.println(\"channelActive attributeMap 中是有值的\");\n            System.out.println(nChannel.getName() + \"=======\" + nChannel.getCreateDate());\n        }\n        System.out.println(\"HelloWorldC0ientHandler Active\");\n        ctx.fireChannelActive();\n    }\n\n    @Override\n    public void channelRead(ChannelHandlerContext ctx, Object msg) {\n        Attribute<NettyChannel> attr = ctx.channel().attr(NETTY_CHANNEL_KEY);\n        NettyChannel nChannel = attr.get();\n        if (nChannel == null) {\n            NettyChannel newNChannel = new NettyChannel(\"HelloWorld0Client\", new Date());\n            nChannel = attr.setIfAbsent(newNChannel);\n        } else {\n            System.out.println(\"channelRead attributeMap 中是有值的\");\n            System.out.println(nChannel.getName() + \"=======\" + nChannel.getCreateDate());\n        }\n        System.out.println(\"HelloWorldClientHandler read Message:\" + msg);\n        \n        ctx.fireChannelRead(msg);\n    }\n\n    @Override\n    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {\n        cause.printStackTrace();\n        ctx.close();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/attributeMap/HelloWorldServer.java",
    "content": "package com.lyncc.netty.attributeMap;\n\nimport io.netty.bootstrap.ServerBootstrap;\nimport io.netty.channel.ChannelFuture;\nimport io.netty.channel.ChannelInitializer;\nimport io.netty.channel.ChannelOption;\nimport io.netty.channel.EventLoopGroup;\nimport io.netty.channel.nio.NioEventLoopGroup;\nimport io.netty.channel.socket.SocketChannel;\nimport io.netty.channel.socket.nio.NioServerSocketChannel;\nimport io.netty.handler.codec.string.StringDecoder;\nimport io.netty.handler.codec.string.StringEncoder;\n\nimport java.net.InetSocketAddress;\n\npublic class HelloWorldServer {\n\n    private int port;\n    \n    public HelloWorldServer(int port) {\n        this.port = port;\n    }\n    \n    public void start(){\n        EventLoopGroup bossGroup = new NioEventLoopGroup(1);\n        EventLoopGroup workerGroup = new NioEventLoopGroup();\n        try {\n            ServerBootstrap sbs = new ServerBootstrap().group(bossGroup,workerGroup).channel(NioServerSocketChannel.class).localAddress(new InetSocketAddress(port))\n                    .childHandler(new ChannelInitializer<SocketChannel>() {\n                        \n                        protected void initChannel(SocketChannel ch) throws Exception {\n                            ch.pipeline().addLast(\"decoder\", new StringDecoder());\n                            ch.pipeline().addLast(\"encoder\", new StringEncoder());\n                            ch.pipeline().addLast(new HelloWorldServerHandler());\n                        };\n                        \n                    }).option(ChannelOption.SO_BACKLOG, 128)   \n                    .childOption(ChannelOption.SO_KEEPALIVE, true);\n             // 绑定端口，开始接收进来的连接\n             ChannelFuture future = sbs.bind(port).sync();  \n             \n             System.out.println(\"Server start listen at \" + port );\n             future.channel().closeFuture().sync();\n        } catch (Exception e) {\n            bossGroup.shutdownGracefully();\n            workerGroup.shutdownGracefully();\n        }\n    }\n    \n    public static void main(String[] args) throws Exception {\n        int port;\n        if (args.length > 0) {\n            port = Integer.parseInt(args[0]);\n        } else {\n            port = 8080;\n        }\n        new HelloWorldServer(port).start();\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/attributeMap/HelloWorldServerHandler.java",
    "content": "package com.lyncc.netty.attributeMap;\n\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.channel.ChannelInboundHandlerAdapter;\n\npublic class HelloWorldServerHandler extends ChannelInboundHandlerAdapter{\n    \n    \n    @Override\n    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {\n        System.out.println(\"server channelRead..\");\n        System.out.println(ctx.channel().remoteAddress()+\"->Server :\"+ msg.toString());\n        ctx.write(\"server write\"+msg);\n        ctx.flush();\n    }\n    \n    @Override\n    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {\n        cause.printStackTrace();\n        ctx.close();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/attributeMap/NettyChannel.java",
    "content": "package com.lyncc.netty.attributeMap;\n\nimport java.util.Date;\n\npublic class NettyChannel {\n    \n    private String name;\n    \n    \n    private Date createDate;\n\n\n    public NettyChannel(String name,Date createDate) {\n        this.name = name;\n        this.createDate = createDate;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n\n    public Date getCreateDate() {\n        return createDate;\n    }\n\n    public void setCreateDate(Date createDate) {\n        this.createDate = createDate;\n    }\n    \n\n}\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/codec/custom/ProtocolDecoder.java",
    "content": "package com.lyncc.netty.codec.custom;\r\n\r\n\r\npublic class ProtocolDecoder{\r\n\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/codec/custom/ProtocolEncoder.java",
    "content": "package com.lyncc.netty.codec.custom;\r\n\r\nimport java.nio.charset.Charset;\r\n\r\nimport io.netty.buffer.ByteBuf;\r\nimport io.netty.channel.ChannelHandlerContext;\r\nimport io.netty.handler.codec.MessageToByteEncoder;\r\n\r\npublic class ProtocolEncoder extends MessageToByteEncoder<ProtocolMsg> {\r\n\r\n    @Override\r\n    protected void encode(ChannelHandlerContext ctx, ProtocolMsg msg, ByteBuf out) throws Exception {\r\n        if (null == msg || null == msg.getProtocolHeader()) {\r\n             throw new Exception(\"msg is null\");\r\n        }\r\n        \r\n        ProtocolHeader header = msg.getProtocolHeader();\r\n        String body = msg.getBody();\r\n        \r\n        byte[] bodyBytes = body.getBytes(Charset.forName(\"utf-8\"));\r\n        int bodySize = bodyBytes.length;\r\n        out.writeByte(header.getMagic());\r\n        out.writeByte(header.getMsgType());\r\n        out.writeShort(header.getReserve());\r\n        out.writeShort(header.getSn());\r\n        out.writeInt(bodySize);\r\n        out.writeBytes(bodyBytes);\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/codec/custom/ProtocolHeader.java",
    "content": "package com.lyncc.netty.codec.custom;\r\n\r\npublic class ProtocolHeader {\r\n    \r\n    private byte magic;\r\n    \r\n    private byte msgType;\r\n    \r\n    private short reserve;\r\n    \r\n    private short sn;\r\n    \r\n    private int len;\r\n    \r\n    public ProtocolHeader() {\r\n        \r\n    }\r\n\r\n    public byte getMagic() {\r\n        return magic;\r\n    }\r\n\r\n    public void setMagic(byte magic) {\r\n        this.magic = magic;\r\n    }\r\n\r\n    public byte getMsgType() {\r\n        return msgType;\r\n    }\r\n\r\n    public void setMsgType(byte msgType) {\r\n        this.msgType = msgType;\r\n    }\r\n\r\n    public short getReserve() {\r\n        return reserve;\r\n    }\r\n\r\n    public void setReserve(short reserve) {\r\n        this.reserve = reserve;\r\n    }\r\n\r\n    public short getSn() {\r\n        return sn;\r\n    }\r\n\r\n    public void setSn(short sn) {\r\n        this.sn = sn;\r\n    }\r\n\r\n    public int getLen() {\r\n        return len;\r\n    }\r\n\r\n    public void setLen(int len) {\r\n        this.len = len;\r\n    }\r\n\r\n    public ProtocolHeader(byte magic, byte msgType, short reserve, short sn, int len) {\r\n        this.magic = magic;\r\n        this.msgType = msgType;\r\n        this.reserve = reserve;\r\n        this.sn = sn;\r\n        this.len = len;\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/codec/custom/ProtocolMsg.java",
    "content": "package com.lyncc.netty.codec.custom;\r\n\r\npublic class ProtocolMsg {\r\n    \r\n    private ProtocolHeader protocolHeader = new ProtocolHeader();\r\n    \r\n    private String body;\r\n    \r\n    public ProtocolMsg() {\r\n        \r\n    }\r\n\r\n    public ProtocolHeader getProtocolHeader() {\r\n        return protocolHeader;\r\n    }\r\n\r\n    public void setProtocolHeader(ProtocolHeader protocolHeader) {\r\n        this.protocolHeader = protocolHeader;\r\n    }\r\n\r\n    public String getBody() {\r\n        return body;\r\n    }\r\n\r\n    public void setBody(String body) {\r\n        this.body = body;\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/codec/jackson/JacksonClient.java",
    "content": "package com.lyncc.netty.codec.jackson;\r\n\r\nimport io.netty.bootstrap.Bootstrap;\r\nimport io.netty.channel.Channel;\r\nimport io.netty.channel.EventLoopGroup;\r\nimport io.netty.channel.nio.NioEventLoopGroup;\r\nimport io.netty.channel.socket.nio.NioSocketChannel;\r\n\r\nimport java.util.ArrayList;\r\nimport java.util.List;\r\n\r\n\r\npublic class JacksonClient {\r\n\r\n    private final String host;\r\n    private final int port;\r\n\r\n    public JacksonClient(String host, int port){\r\n        this.host = host;\r\n        this.port = port;\r\n    }\r\n    \r\n    public static void main(String[] args) throws Exception{\r\n        new JacksonClient(\"localhost\", 8082).run();\r\n    }\r\n    \r\n    public void run() throws Exception{\r\n        EventLoopGroup group = new NioEventLoopGroup();\r\n        try {\r\n            Bootstrap bootstrap  = new Bootstrap()\r\n                    .group(group)\r\n                    .channel(NioSocketChannel.class)\r\n                    .handler(new JacksonClientHandlerInitializer());\r\n            \r\n            Channel channel = bootstrap.connect(host, port).sync().channel();\r\n\r\n            // 发送对象\r\n            User user = new User();\r\n            user.setId(1);\r\n            user.setAge(21);\r\n            user.setName(\"BazingaLyncc\");\r\n            \r\n            List<String> friends = new ArrayList<String>();\r\n            friends.add(\"TED\");\r\n            friends.add(\"MISS\");\r\n            user.setFriends(friends);\r\n            \r\n            channel.write(user);\r\n            channel.flush();\r\n \r\n            // 等待连接关闭\r\n            channel.closeFuture().sync();\r\n        } catch (Exception e) {\r\n            e.printStackTrace();\r\n        } finally {\r\n            group.shutdownGracefully();\r\n        }\r\n\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/codec/jackson/JacksonClientHandler.java",
    "content": "package com.lyncc.netty.codec.jackson;\r\n\r\nimport io.netty.channel.ChannelHandlerContext;\r\nimport io.netty.channel.SimpleChannelInboundHandler;\r\n\r\npublic class JacksonClientHandler extends SimpleChannelInboundHandler<Object>{\r\n\r\n    @Override\r\n    protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {\r\n        String jsonString = \"\";\r\n        if (msg instanceof User) {\r\n            User user = (User) msg;\r\n            \r\n            jsonString = UserMapper.getInstance().writeValueAsString(user);  \r\n        } else {\r\n            jsonString = UserMapper.getInstance().writeValueAsString(msg);  \r\n        }\r\n        System.out.println(\"Client get msg form Server -\" + jsonString);\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/codec/jackson/JacksonClientHandlerInitializer.java",
    "content": "package com.lyncc.netty.codec.jackson;\r\n\r\nimport io.netty.channel.Channel;\r\nimport io.netty.channel.ChannelInitializer;\r\nimport io.netty.channel.ChannelPipeline;\r\n\r\npublic class JacksonClientHandlerInitializer extends ChannelInitializer<Channel>{\r\n\r\n    @Override\r\n    protected void initChannel(Channel ch) throws Exception {\r\n        ChannelPipeline pipeline = ch.pipeline();\r\n        pipeline.addLast(new UserDecoder<User>(User.class));\r\n        pipeline.addLast(new UserEncoder());\r\n        pipeline.addLast(new JacksonClientHandler());\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/codec/jackson/JacksonServer.java",
    "content": "package com.lyncc.netty.codec.jackson;\r\n\r\nimport io.netty.bootstrap.ServerBootstrap;\r\nimport io.netty.channel.ChannelFuture;\r\nimport io.netty.channel.ChannelOption;\r\nimport io.netty.channel.EventLoopGroup;\r\nimport io.netty.channel.nio.NioEventLoopGroup;\r\nimport io.netty.channel.socket.nio.NioServerSocketChannel;\r\nimport io.netty.handler.logging.LogLevel;\r\nimport io.netty.handler.logging.LoggingHandler;\r\n\r\npublic class JacksonServer {\r\n    \r\n    static final int PORT = 8082;\r\n    \r\n    public static void main(String[] args) {\r\n        \r\n        EventLoopGroup bossGroup = new NioEventLoopGroup(1);\r\n        EventLoopGroup workerGroup = new NioEventLoopGroup();\r\n        \r\n        try {\r\n            ServerBootstrap serverBootstrap = new ServerBootstrap().group(bossGroup,workerGroup)\r\n                    .channel(NioServerSocketChannel.class)\r\n                    .option(ChannelOption.SO_BACKLOG, 100)\r\n                    .childOption(ChannelOption.SO_KEEPALIVE, true)\r\n                    .handler(new LoggingHandler(LogLevel.INFO))\r\n                    .childHandler(new JacksonServerHandlerInitializer());\r\n            ChannelFuture f = serverBootstrap.bind(PORT).sync();\r\n            \r\n            System.out.println(\"Server start listen at \" + PORT );\r\n            f.channel().closeFuture().sync();\r\n        } catch (Exception e) {\r\n            bossGroup.shutdownGracefully();\r\n            workerGroup.shutdownGracefully();\r\n        }\r\n        \r\n        \r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/codec/jackson/JacksonServerHandler.java",
    "content": "package com.lyncc.netty.codec.jackson;\r\n\r\nimport io.netty.channel.Channel;\r\nimport io.netty.channel.ChannelHandlerContext;\r\nimport io.netty.channel.SimpleChannelInboundHandler;\r\n\r\npublic class JacksonServerHandler extends SimpleChannelInboundHandler<Object> {\r\n\r\n    @Override\r\n    protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {\r\n        String jsonString = \"\";\r\n        if (msg instanceof User) {\r\n            \r\n            User user = (User)msg;\r\n            ctx.writeAndFlush(user);\r\n            \r\n            jsonString = UserMapper.getInstance().writeValueAsString(user); \r\n        } else {\r\n            ctx.writeAndFlush(msg);\r\n            jsonString = UserMapper.getInstance().writeValueAsString(msg);\r\n        }\r\n        System.out.println(\"Server get msg form Client -\" + jsonString);\r\n    }\r\n    \r\n    @Override\r\n    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { \r\n        Channel incoming = ctx.channel();\r\n        System.out.println(\"SimpleChatClient:\"+incoming.remoteAddress()+\"异常\");\r\n        cause.printStackTrace();\r\n        ctx.close();\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/codec/jackson/JacksonServerHandlerInitializer.java",
    "content": "package com.lyncc.netty.codec.jackson;\r\n\r\nimport io.netty.channel.ChannelInitializer;\r\nimport io.netty.channel.ChannelPipeline;\r\nimport io.netty.channel.socket.SocketChannel;\r\n\r\npublic class JacksonServerHandlerInitializer extends ChannelInitializer<SocketChannel>{\r\n\r\n    @Override\r\n    protected void initChannel(SocketChannel ch) throws Exception {\r\n        ChannelPipeline pipeline = ch.pipeline();\r\n        pipeline.addLast(new UserDecoder<User>(User.class));\r\n        pipeline.addLast(new UserEncoder());\r\n        pipeline.addLast(new JacksonServerHandler());\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/codec/jackson/User.java",
    "content": "package com.lyncc.netty.codec.jackson;\r\n\r\nimport java.util.List;\r\n\r\npublic class User {\r\n    \r\n    private Integer id;\r\n    \r\n    private String name;\r\n    \r\n    private Integer age;\r\n    \r\n    private List<String> friends;\r\n\r\n    public Integer getId() {\r\n        return id;\r\n    }\r\n\r\n    public void setId(Integer id) {\r\n        this.id = id;\r\n    }\r\n\r\n    public String getName() {\r\n        return name;\r\n    }\r\n\r\n    public void setName(String name) {\r\n        this.name = name;\r\n    }\r\n\r\n    public Integer getAge() {\r\n        return age;\r\n    }\r\n\r\n    public void setAge(Integer age) {\r\n        this.age = age;\r\n    }\r\n\r\n    public List<String> getFriends() {\r\n        return friends;\r\n    }\r\n\r\n    public void setFriends(List<String> friends) {\r\n        this.friends = friends;\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/codec/jackson/UserDecoder.java",
    "content": "package com.lyncc.netty.codec.jackson;\r\n\r\nimport io.netty.buffer.ByteBuf;\r\nimport io.netty.buffer.ByteBufInputStream;\r\nimport io.netty.channel.ChannelHandlerContext;\r\nimport io.netty.handler.codec.ByteToMessageDecoder;\r\n\r\nimport java.util.List;\r\n\r\npublic class UserDecoder<T> extends ByteToMessageDecoder {\r\n    \r\n    private final Class<T> clazz;\r\n    \r\n    \r\n    public UserDecoder(Class<T> clazz) {\r\n        this.clazz = clazz;\r\n    }\r\n\r\n    @Override\r\n    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {\r\n        ByteBufInputStream byteBufInputStream = new ByteBufInputStream(in);\r\n        out.add(UserMapper.getInstance().readValue(byteBufInputStream, clazz));\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/codec/jackson/UserEncoder.java",
    "content": "package com.lyncc.netty.codec.jackson;\r\n\r\nimport io.netty.buffer.ByteBuf;\r\nimport io.netty.buffer.ByteBufOutputStream;\r\nimport io.netty.channel.ChannelHandlerContext;\r\nimport io.netty.handler.codec.MessageToByteEncoder;\r\n\r\npublic class UserEncoder extends MessageToByteEncoder<Object>{\r\n\r\n    @Override\r\n    protected void encode(ChannelHandlerContext ctx, Object msg, ByteBuf out) throws Exception {\r\n        ByteBufOutputStream byteBufOutputStream = new ByteBufOutputStream(out);\r\n        UserMapper.getInstance().writeValue(byteBufOutputStream, msg);\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/codec/jackson/UserMapper.java",
    "content": "package com.lyncc.netty.codec.jackson;\r\n\r\nimport com.fasterxml.jackson.databind.ObjectMapper;\r\n\r\npublic class UserMapper {\r\n    \r\n    private static final ObjectMapper MAPPER = new ObjectMapper();\r\n\r\n    public static ObjectMapper getInstance() {\r\n        return MAPPER;\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/codec/lengthFieldBasedFrame/CustomClient.java",
    "content": "package com.lyncc.netty.codec.lengthFieldBasedFrame;\r\n\r\nimport io.netty.bootstrap.Bootstrap;\r\nimport io.netty.channel.ChannelFuture;\r\nimport io.netty.channel.ChannelInitializer;\r\nimport io.netty.channel.ChannelOption;\r\nimport io.netty.channel.EventLoopGroup;\r\nimport io.netty.channel.nio.NioEventLoopGroup;\r\nimport io.netty.channel.socket.SocketChannel;\r\nimport io.netty.channel.socket.nio.NioSocketChannel;\r\n\r\npublic class CustomClient {\r\n    \r\n    static final String HOST = System.getProperty(\"host\", \"127.0.0.1\");\r\n    static final int PORT = Integer.parseInt(System.getProperty(\"port\", \"8080\"));\r\n    static final int SIZE = Integer.parseInt(System.getProperty(\"size\", \"256\"));\r\n\r\n    public static void main(String[] args) throws Exception {\r\n\r\n        // Configure the client.\r\n        EventLoopGroup group = new NioEventLoopGroup();\r\n        try {\r\n            Bootstrap b = new Bootstrap();\r\n            b.group(group)\r\n             .channel(NioSocketChannel.class)\r\n             .option(ChannelOption.TCP_NODELAY, true)\r\n             .handler(new ChannelInitializer<SocketChannel>() {\r\n                 @Override\r\n                 public void initChannel(SocketChannel ch) throws Exception {\r\n                     ch.pipeline().addLast(new CustomEncoder());\r\n                     ch.pipeline().addLast(new CustomClientHandler());\r\n                 }\r\n             });\r\n\r\n            ChannelFuture future = b.connect(HOST, PORT).sync();\r\n            future.channel().writeAndFlush(\"Hello Netty Server ,I am a common client\");\r\n            future.channel().closeFuture().sync();\r\n        } finally {\r\n            group.shutdownGracefully();\r\n        }\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/codec/lengthFieldBasedFrame/CustomClientHandler.java",
    "content": "package com.lyncc.netty.codec.lengthFieldBasedFrame;\r\n\r\nimport io.netty.channel.ChannelHandlerContext;\r\nimport io.netty.channel.ChannelInboundHandlerAdapter;\r\n\r\npublic class CustomClientHandler extends ChannelInboundHandlerAdapter {\r\n    \r\n    @Override\r\n    public void channelActive(ChannelHandlerContext ctx) throws Exception {\r\n        CustomMsg customMsg = new CustomMsg((byte)0xAB, (byte)0xCD, \"Hello,Netty\".length(), \"Hello,Netty\");\r\n        ctx.writeAndFlush(customMsg);\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/codec/lengthFieldBasedFrame/CustomDecoder.java",
    "content": "package com.lyncc.netty.codec.lengthFieldBasedFrame;\r\n\r\nimport io.netty.buffer.ByteBuf;\r\nimport io.netty.channel.ChannelHandlerContext;\r\nimport io.netty.handler.codec.LengthFieldBasedFrameDecoder;\r\n\r\npublic class CustomDecoder extends LengthFieldBasedFrameDecoder {\r\n    \r\n    //判断传送客户端传送过来的数据是否按照协议传输，头部信息的大小应该是 byte+byte+int = 1+1+4 = 6\r\n    private static final int HEADER_SIZE = 6;\r\n    \r\n    private byte type;\r\n    \r\n    private byte flag;\r\n    \r\n    private int length;\r\n    \r\n    private String body;\r\n\r\n    /**\r\n     * \r\n     * @param maxFrameLength 解码时，处理每个帧数据的最大长度\r\n     * @param lengthFieldOffset 该帧数据中，存放该帧数据的长度的数据的起始位置\r\n     * @param lengthFieldLength 记录该帧数据长度的字段本身的长度\r\n     * @param lengthAdjustment 修改帧数据长度字段中定义的值，可以为负数\r\n     * @param initialBytesToStrip 解析的时候需要跳过的字节数\r\n     * @param failFast 为true，当frame长度超过maxFrameLength时立即报TooLongFrameException异常，为false，读取完整个帧再报异常\r\n     */\r\n    public CustomDecoder(int maxFrameLength, int lengthFieldOffset, int lengthFieldLength,\r\n            int lengthAdjustment, int initialBytesToStrip, boolean failFast) {\r\n        super(maxFrameLength, lengthFieldOffset, lengthFieldLength,\r\n                lengthAdjustment, initialBytesToStrip, failFast);\r\n    }\r\n    \r\n    @Override\r\n    protected Object decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {\r\n        if (in == null) {\r\n            return null;\r\n        }\r\n        if (in.readableBytes() < HEADER_SIZE) {\r\n            throw new Exception(\"可读信息段比头部信息都小，你在逗我？\");\r\n        }\r\n        \r\n        //注意在读的过程中，readIndex的指针也在移动\r\n        type = in.readByte();\r\n        \r\n        flag = in.readByte();\r\n        \r\n        length = in.readInt();\r\n        \r\n        if (in.readableBytes() < length) {\r\n            throw new Exception(\"body字段你告诉我长度是\"+length+\",但是真实情况是没有这么多，你又逗我？\");\r\n        }\r\n        ByteBuf buf = in.readBytes(length);\r\n        byte[] req = new byte[buf.readableBytes()];\r\n        buf.readBytes(req);\r\n        body = new String(req, \"UTF-8\");\r\n        \r\n        CustomMsg customMsg = new CustomMsg(type,flag,length,body);\r\n        return customMsg;\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/codec/lengthFieldBasedFrame/CustomEncoder.java",
    "content": "package com.lyncc.netty.codec.lengthFieldBasedFrame;\r\n\r\nimport java.nio.charset.Charset;\r\n\r\nimport io.netty.buffer.ByteBuf;\r\nimport io.netty.channel.ChannelHandlerContext;\r\nimport io.netty.handler.codec.MessageToByteEncoder;\r\n\r\npublic class CustomEncoder extends MessageToByteEncoder<CustomMsg> {\r\n\r\n    @Override\r\n    protected void encode(ChannelHandlerContext ctx, CustomMsg msg, ByteBuf out) throws Exception {\r\n        if(null == msg){\r\n            throw new Exception(\"msg is null\");\r\n        }\r\n        \r\n        String body = msg.getBody();\r\n        byte[] bodyBytes = body.getBytes(Charset.forName(\"utf-8\"));\r\n        out.writeByte(msg.getType());\r\n        out.writeByte(msg.getFlag());\r\n        out.writeInt(bodyBytes.length);\r\n        out.writeBytes(bodyBytes);\r\n        \r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/codec/lengthFieldBasedFrame/CustomMsg.java",
    "content": "package com.lyncc.netty.codec.lengthFieldBasedFrame;\r\n\r\npublic class CustomMsg {\r\n    \r\n    //类型  系统编号 0xAB 表示A系统，0xBC 表示B系统\r\n    private byte type;\r\n    \r\n    //信息标志  0xAB 表示心跳包    0xBC 表示超时包  0xCD 业务信息包\r\n    private byte flag;\r\n    \r\n    //主题信息的长度\r\n    private int length;\r\n    \r\n    //主题信息\r\n    private String body;\r\n    \r\n    public CustomMsg() {\r\n        \r\n    }\r\n    \r\n    public CustomMsg(byte type, byte flag, int length, String body) {\r\n        this.type = type;\r\n        this.flag = flag;\r\n        this.length = length;\r\n        this.body = body;\r\n    }\r\n\r\n    public byte getType() {\r\n        return type;\r\n    }\r\n\r\n    public void setType(byte type) {\r\n        this.type = type;\r\n    }\r\n\r\n    public byte getFlag() {\r\n        return flag;\r\n    }\r\n\r\n    public void setFlag(byte flag) {\r\n        this.flag = flag;\r\n    }\r\n\r\n    public int getLength() {\r\n        return length;\r\n    }\r\n\r\n    public void setLength(int length) {\r\n        this.length = length;\r\n    }\r\n\r\n    public String getBody() {\r\n        return body;\r\n    }\r\n\r\n    public void setBody(String body) {\r\n        this.body = body;\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/codec/lengthFieldBasedFrame/CustomServer.java",
    "content": "package com.lyncc.netty.codec.lengthFieldBasedFrame;\r\n\r\nimport io.netty.bootstrap.ServerBootstrap;\r\nimport io.netty.channel.ChannelFuture;\r\nimport io.netty.channel.ChannelInitializer;\r\nimport io.netty.channel.ChannelOption;\r\nimport io.netty.channel.EventLoopGroup;\r\nimport io.netty.channel.nio.NioEventLoopGroup;\r\nimport io.netty.channel.socket.SocketChannel;\r\nimport io.netty.channel.socket.nio.NioServerSocketChannel;\r\n\r\nimport java.net.InetSocketAddress;\r\n\r\npublic class CustomServer {\r\n    \r\n    private static final int MAX_FRAME_LENGTH = 1024 * 1024;\r\n    private static final int LENGTH_FIELD_LENGTH = 4;\r\n    private static final int LENGTH_FIELD_OFFSET = 2;\r\n    private static final int LENGTH_ADJUSTMENT = 0;\r\n    private static final int INITIAL_BYTES_TO_STRIP = 0;\r\n\r\n    private int port;\r\n    \r\n    public CustomServer(int port) {\r\n        this.port = port;\r\n    }\r\n    \r\n    public void start(){\r\n        EventLoopGroup bossGroup = new NioEventLoopGroup(1);\r\n        EventLoopGroup workerGroup = new NioEventLoopGroup();\r\n        try {\r\n            ServerBootstrap sbs = new ServerBootstrap().group(bossGroup,workerGroup).channel(NioServerSocketChannel.class).localAddress(new InetSocketAddress(port))\r\n                    .childHandler(new ChannelInitializer<SocketChannel>() {\r\n                        \r\n                        protected void initChannel(SocketChannel ch) throws Exception {\r\n                             ch.pipeline().addLast(new CustomDecoder(MAX_FRAME_LENGTH,LENGTH_FIELD_LENGTH,LENGTH_FIELD_OFFSET,LENGTH_ADJUSTMENT,INITIAL_BYTES_TO_STRIP,false));\r\n                             ch.pipeline().addLast(new CustomServerHandler());\r\n                        };\r\n                        \r\n                    }).option(ChannelOption.SO_BACKLOG, 128)   \r\n                    .childOption(ChannelOption.SO_KEEPALIVE, true);\r\n             // 绑定端口，开始接收进来的连接\r\n             ChannelFuture future = sbs.bind(port).sync();  \r\n             \r\n             System.out.println(\"Server start listen at \" + port );\r\n             future.channel().closeFuture().sync();\r\n        } catch (Exception e) {\r\n            bossGroup.shutdownGracefully();\r\n            workerGroup.shutdownGracefully();\r\n        }\r\n    }\r\n    \r\n    public static void main(String[] args) throws Exception {\r\n        int port;\r\n        if (args.length > 0) {\r\n            port = Integer.parseInt(args[0]);\r\n        } else {\r\n            port = 8080;\r\n        }\r\n        new CustomServer(port).start();\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/codec/lengthFieldBasedFrame/CustomServerHandler.java",
    "content": "package com.lyncc.netty.codec.lengthFieldBasedFrame;\r\n\r\nimport io.netty.channel.ChannelHandlerContext;\r\nimport io.netty.channel.SimpleChannelInboundHandler;\r\n\r\npublic class CustomServerHandler extends SimpleChannelInboundHandler<Object> {\r\n\r\n    @Override\r\n    protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {\r\n        if(msg instanceof CustomMsg) {\r\n            CustomMsg customMsg = (CustomMsg)msg;\r\n            System.out.println(\"Client->Server:\"+ctx.channel().remoteAddress()+\" send \"+customMsg.getBody());\r\n        }\r\n        \r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/codec/protobuf/SubReqClient.java",
    "content": "/*\n * Copyright 2012 The Netty Project\n *\n * The Netty Project licenses this file to you under the Apache License,\n * version 2.0 (the \"License\"); you may not use this file except in compliance\n * with the License. You may obtain a copy of the License at:\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\npackage com.lyncc.netty.codec.protobuf;\n\nimport io.netty.bootstrap.Bootstrap;\nimport io.netty.channel.ChannelFuture;\nimport io.netty.channel.ChannelInitializer;\nimport io.netty.channel.ChannelOption;\nimport io.netty.channel.EventLoopGroup;\nimport io.netty.channel.nio.NioEventLoopGroup;\nimport io.netty.channel.socket.SocketChannel;\nimport io.netty.channel.socket.nio.NioSocketChannel;\nimport io.netty.handler.codec.protobuf.ProtobufDecoder;\nimport io.netty.handler.codec.protobuf.ProtobufEncoder;\nimport io.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder;\nimport io.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender;\n\n/**\n * @author lilinfeng\n * @date 2014年2月14日\n * @version 1.0\n */\npublic class SubReqClient {\n\n    public void connect(int port, String host) throws Exception {\n        // 配置客户端NIO线程组\n        EventLoopGroup group = new NioEventLoopGroup();\n        try {\n            Bootstrap b = new Bootstrap();\n            b.group(group).channel(NioSocketChannel.class).option(ChannelOption.TCP_NODELAY, true)\n                    .handler(new ChannelInitializer<SocketChannel>() {\n                        @Override\n                        public void initChannel(SocketChannel ch) throws Exception {\n                            ch.pipeline().addLast(new ProtobufVarint32FrameDecoder());\n                            ch.pipeline().addLast(new ProtobufDecoder(SubscribeRespProto.SubscribeResp.getDefaultInstance()));\n                            ch.pipeline().addLast(new ProtobufVarint32LengthFieldPrepender());\n                            ch.pipeline().addLast(new ProtobufEncoder());\n                            ch.pipeline().addLast(new SubReqClientHandler());\n                        }\n                    });\n\n            // 发起异步连接操作\n            ChannelFuture f = b.connect(host, port).sync();\n\n            // 当代客户端链路关闭\n            f.channel().closeFuture().sync();\n        } finally {\n            // 优雅退出，释放NIO线程组\n            group.shutdownGracefully();\n        }\n    }\n\n    /**\n     * @param args\n     * @throws Exception\n     */\n    public static void main(String[] args) throws Exception {\n        int port = 8080;\n        if (args != null && args.length > 0) {\n            try {\n                port = Integer.valueOf(args[0]);\n            } catch (NumberFormatException e) {\n                // 采用默认值\n            }\n        }\n        new SubReqClient().connect(port, \"127.0.0.1\");\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/codec/protobuf/SubReqClientHandler.java",
    "content": "/*\n * Copyright 2012 The Netty Project\n *\n * The Netty Project licenses this file to you under the Apache License,\n * version 2.0 (the \"License\"); you may not use this file except in compliance\n * with the License. You may obtain a copy of the License at:\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\npackage com.lyncc.netty.codec.protobuf;\n\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.channel.ChannelInboundHandlerAdapter;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * @author lilinfeng\n * @date 2014年2月14日\n * @version 1.0\n */\npublic class SubReqClientHandler extends ChannelInboundHandlerAdapter {\n\n    /**\n     * Creates a client-side handler.\n     */\n    public SubReqClientHandler() {\n    }\n\n    @Override\n    public void channelActive(ChannelHandlerContext ctx) {\n        for (int i = 0; i < 10; i++) {\n            ctx.write(subReq(i));\n        }\n        ctx.flush();\n    }\n\n    private SubscribeReqProto.SubscribeReq subReq(int i) {\n        SubscribeReqProto.SubscribeReq.Builder builder = SubscribeReqProto.SubscribeReq.newBuilder();\n        builder.setSubReqID(i);\n        builder.setUserName(\"Lilinfeng\");\n        builder.setProductName(\"Netty Book For Protobuf\");\n        List<String> address = new ArrayList<String>();\n        address.add(\"NanJing YuHuaTai\");\n        address.add(\"BeiJing LiuLiChang\");\n        address.add(\"ShenZhen HongShuLin\");\n        builder.addAllAddress(address);\n        return builder.build();\n    }\n\n    @Override\n    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {\n        System.out.println(\"Receive server response : [\" + msg + \"]\");\n    }\n\n    @Override\n    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {\n        ctx.flush();\n    }\n\n    @Override\n    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {\n        cause.printStackTrace();\n        ctx.close();\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/codec/protobuf/SubReqServer.java",
    "content": "package com.lyncc.netty.codec.protobuf;\r\n\r\nimport io.netty.bootstrap.ServerBootstrap;\r\nimport io.netty.channel.ChannelFuture;\r\nimport io.netty.channel.ChannelInitializer;\r\nimport io.netty.channel.ChannelOption;\r\nimport io.netty.channel.EventLoopGroup;\r\nimport io.netty.channel.nio.NioEventLoopGroup;\r\nimport io.netty.channel.socket.SocketChannel;\r\nimport io.netty.channel.socket.nio.NioServerSocketChannel;\r\nimport io.netty.handler.codec.protobuf.ProtobufDecoder;\r\nimport io.netty.handler.codec.protobuf.ProtobufEncoder;\r\nimport io.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder;\r\nimport io.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender;\r\nimport io.netty.handler.logging.LogLevel;\r\nimport io.netty.handler.logging.LoggingHandler;\r\n\r\npublic class SubReqServer {\r\n\r\n    public void bind(int port) throws Exception {\r\n        // 配置服务端的NIO线程组\r\n        EventLoopGroup bossGroup = new NioEventLoopGroup();\r\n        EventLoopGroup workerGroup = new NioEventLoopGroup();\r\n        try {\r\n            ServerBootstrap b = new ServerBootstrap();\r\n            b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).option(ChannelOption.SO_BACKLOG, 100)\r\n                    .handler(new LoggingHandler(LogLevel.INFO)).childHandler(new ChannelInitializer<SocketChannel>() {\r\n                        @Override\r\n                        public void initChannel(SocketChannel ch) {\r\n                            ch.pipeline().addLast(new ProtobufVarint32FrameDecoder());\r\n                            ch.pipeline().addLast(new ProtobufDecoder(SubscribeReqProto.SubscribeReq.getDefaultInstance()));\r\n                            ch.pipeline().addLast(new ProtobufVarint32LengthFieldPrepender());\r\n                            ch.pipeline().addLast(new ProtobufEncoder());\r\n                            ch.pipeline().addLast(new SubReqServerHandler());\r\n                        }\r\n                    });\r\n\r\n            // 绑定端口，同步等待成功\r\n            ChannelFuture f = b.bind(port).sync();\r\n\r\n            System.out.println(\"init start\");\r\n            // 等待服务端监听端口关闭\r\n            f.channel().closeFuture().sync();\r\n        } finally {\r\n            // 优雅退出，释放线程池资源\r\n            bossGroup.shutdownGracefully();\r\n            workerGroup.shutdownGracefully();\r\n        }\r\n    }\r\n\r\n    public static void main(String[] args) throws Exception {\r\n        int port = 8080;\r\n        if (args != null && args.length > 0) {\r\n            try {\r\n                port = Integer.valueOf(args[0]);\r\n            } catch (NumberFormatException e) {\r\n                // 采用默认值\r\n            }\r\n        }\r\n        new SubReqServer().bind(port);\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/codec/protobuf/SubReqServerHandler.java",
    "content": "/*\n * Copyright 2012 The Netty Project\n *\n * The Netty Project licenses this file to you under the Apache License,\n * version 2.0 (the \"License\"); you may not use this file except in compliance\n * with the License. You may obtain a copy of the License at:\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\npackage com.lyncc.netty.codec.protobuf;\n\nimport io.netty.channel.ChannelHandler.Sharable;\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.channel.ChannelInboundHandlerAdapter;\n\n@Sharable\npublic class SubReqServerHandler extends ChannelInboundHandlerAdapter {\n\n\n    @Override\n    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {\n        SubscribeReqProto.SubscribeReq req = (SubscribeReqProto.SubscribeReq) msg;\n        if (\"Lilinfeng\".equalsIgnoreCase(req.getUserName())) {\n            System.out.println(\"Service accept client subscribe req : [\" + req.toString() + \"]\");\n            ctx.writeAndFlush(resp(req.getSubReqID()));\n        }\n    }\n\n    private SubscribeRespProto.SubscribeResp resp(int subReqID) {\n        SubscribeRespProto.SubscribeResp.Builder builder = SubscribeRespProto.SubscribeResp.newBuilder();\n        builder.setSubReqID(subReqID);\n        builder.setRespCode(0);\n        builder.setDesc(\"Netty book order succeed, 3 days later, sent to the designated address\");\n        return builder.build();\n    }\n\n    @Override\n    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {\n        cause.printStackTrace();\n        ctx.close();// 发生异常，关闭链路\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/codec/protobuf/SubscribeReq.proto",
    "content": "package netty;  \r\noption java_package = \"com.lyncc.netty.codec.protobuf\";  \r\noption java_outer_classname = \"SubscribeReqProto\";  \r\n  \r\nmessage SubscribeReq{  \r\n    required int32 subReqID = 1;  \r\n    required string userName = 2;  \r\n    required string productName = 3;  \r\n    repeated string address = 4;  \r\n} "
  },
  {
    "path": "src/main/java/com/lyncc/netty/codec/protobuf/SubscribeReqProto.java",
    "content": "// Generated by the protocol buffer compiler.  DO NOT EDIT!\n// source: SubscribeReq.proto\n\npackage com.lyncc.netty.codec.protobuf;\n\npublic final class SubscribeReqProto {\n    private SubscribeReqProto() {\n    }\n\n    public static void registerAllExtensions(com.google.protobuf.ExtensionRegistry registry) {\n    }\n\n    public interface SubscribeReqOrBuilder extends\n    // @@protoc_insertion_point(interface_extends:netty.SubscribeReq)\n            com.google.protobuf.MessageOrBuilder {\n\n        /**\n         * <code>required int32 subReqID = 1;</code>\n         */\n        boolean hasSubReqID();\n\n        /**\n         * <code>required int32 subReqID = 1;</code>\n         */\n        int getSubReqID();\n\n        /**\n         * <code>required string userName = 2;</code>\n         */\n        boolean hasUserName();\n\n        /**\n         * <code>required string userName = 2;</code>\n         */\n        java.lang.String getUserName();\n\n        /**\n         * <code>required string userName = 2;</code>\n         */\n        com.google.protobuf.ByteString getUserNameBytes();\n\n        /**\n         * <code>required string productName = 3;</code>\n         */\n        boolean hasProductName();\n\n        /**\n         * <code>required string productName = 3;</code>\n         */\n        java.lang.String getProductName();\n\n        /**\n         * <code>required string productName = 3;</code>\n         */\n        com.google.protobuf.ByteString getProductNameBytes();\n\n        /**\n         * <code>repeated string address = 4;</code>\n         */\n        com.google.protobuf.ProtocolStringList getAddressList();\n\n        /**\n         * <code>repeated string address = 4;</code>\n         */\n        int getAddressCount();\n\n        /**\n         * <code>repeated string address = 4;</code>\n         */\n        java.lang.String getAddress(int index);\n\n        /**\n         * <code>repeated string address = 4;</code>\n         */\n        com.google.protobuf.ByteString getAddressBytes(int index);\n    }\n\n    /**\n     * Protobuf type {@code netty.SubscribeReq}\n     */\n    public static final class SubscribeReq extends com.google.protobuf.GeneratedMessage implements\n    // @@protoc_insertion_point(message_implements:netty.SubscribeReq)\n            SubscribeReqOrBuilder {\n        // Use SubscribeReq.newBuilder() to construct.\n        private SubscribeReq(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n            super(builder);\n            this.unknownFields = builder.getUnknownFields();\n        }\n\n        private SubscribeReq(boolean noInit) {\n            this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance();\n        }\n\n        private static final SubscribeReq defaultInstance;\n\n        public static SubscribeReq getDefaultInstance() {\n            return defaultInstance;\n        }\n\n        public SubscribeReq getDefaultInstanceForType() {\n            return defaultInstance;\n        }\n\n        private final com.google.protobuf.UnknownFieldSet unknownFields;\n\n        @java.lang.Override\n        public final com.google.protobuf.UnknownFieldSet getUnknownFields() {\n            return this.unknownFields;\n        }\n\n        private SubscribeReq(com.google.protobuf.CodedInputStream input,\n                com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n                throws com.google.protobuf.InvalidProtocolBufferException {\n            initFields();\n            int mutable_bitField0_ = 0;\n            com.google.protobuf.UnknownFieldSet.Builder unknownFields = com.google.protobuf.UnknownFieldSet\n                    .newBuilder();\n            try {\n                boolean done = false;\n                while (!done) {\n                    int tag = input.readTag();\n                    switch (tag) {\n                    case 0:\n                        done = true;\n                        break;\n                    default: {\n                        if (!parseUnknownField(input, unknownFields, extensionRegistry, tag)) {\n                            done = true;\n                        }\n                        break;\n                    }\n                    case 8: {\n                        bitField0_ |= 0x00000001;\n                        subReqID_ = input.readInt32();\n                        break;\n                    }\n                    case 18: {\n                        com.google.protobuf.ByteString bs = input.readBytes();\n                        bitField0_ |= 0x00000002;\n                        userName_ = bs;\n                        break;\n                    }\n                    case 26: {\n                        com.google.protobuf.ByteString bs = input.readBytes();\n                        bitField0_ |= 0x00000004;\n                        productName_ = bs;\n                        break;\n                    }\n                    case 34: {\n                        com.google.protobuf.ByteString bs = input.readBytes();\n                        if (!((mutable_bitField0_ & 0x00000008) == 0x00000008)) {\n                            address_ = new com.google.protobuf.LazyStringArrayList();\n                            mutable_bitField0_ |= 0x00000008;\n                        }\n                        address_.add(bs);\n                        break;\n                    }\n                    }\n                }\n            } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n                throw e.setUnfinishedMessage(this);\n            } catch (java.io.IOException e) {\n                throw new com.google.protobuf.InvalidProtocolBufferException(e.getMessage()).setUnfinishedMessage(this);\n            } finally {\n                if (((mutable_bitField0_ & 0x00000008) == 0x00000008)) {\n                    address_ = address_.getUnmodifiableView();\n                }\n                this.unknownFields = unknownFields.build();\n                makeExtensionsImmutable();\n            }\n        }\n\n        public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() {\n            return com.lyncc.netty.codec.protobuf.SubscribeReqProto.internal_static_netty_SubscribeReq_descriptor;\n        }\n\n        protected com.google.protobuf.GeneratedMessage.FieldAccessorTable internalGetFieldAccessorTable() {\n            return com.lyncc.netty.codec.protobuf.SubscribeReqProto.internal_static_netty_SubscribeReq_fieldAccessorTable\n                    .ensureFieldAccessorsInitialized(\n                            com.lyncc.netty.codec.protobuf.SubscribeReqProto.SubscribeReq.class,\n                            com.lyncc.netty.codec.protobuf.SubscribeReqProto.SubscribeReq.Builder.class);\n        }\n\n        public static com.google.protobuf.Parser<SubscribeReq> PARSER = new com.google.protobuf.AbstractParser<SubscribeReq>() {\n            public SubscribeReq parsePartialFrom(com.google.protobuf.CodedInputStream input,\n                    com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n                    throws com.google.protobuf.InvalidProtocolBufferException {\n                return new SubscribeReq(input, extensionRegistry);\n            }\n        };\n\n        @java.lang.Override\n        public com.google.protobuf.Parser<SubscribeReq> getParserForType() {\n            return PARSER;\n        }\n\n        private int bitField0_;\n\n        public static final int SUBREQID_FIELD_NUMBER = 1;\n\n        private int subReqID_;\n\n        /**\n         * <code>required int32 subReqID = 1;</code>\n         */\n        public boolean hasSubReqID() {\n            return ((bitField0_ & 0x00000001) == 0x00000001);\n        }\n\n        /**\n         * <code>required int32 subReqID = 1;</code>\n         */\n        public int getSubReqID() {\n            return subReqID_;\n        }\n\n        public static final int USERNAME_FIELD_NUMBER = 2;\n\n        private java.lang.Object userName_;\n\n        /**\n         * <code>required string userName = 2;</code>\n         */\n        public boolean hasUserName() {\n            return ((bitField0_ & 0x00000002) == 0x00000002);\n        }\n\n        /**\n         * <code>required string userName = 2;</code>\n         */\n        public java.lang.String getUserName() {\n            java.lang.Object ref = userName_;\n            if (ref instanceof java.lang.String) {\n                return (java.lang.String) ref;\n            } else {\n                com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref;\n                java.lang.String s = bs.toStringUtf8();\n                if (bs.isValidUtf8()) {\n                    userName_ = s;\n                }\n                return s;\n            }\n        }\n\n        /**\n         * <code>required string userName = 2;</code>\n         */\n        public com.google.protobuf.ByteString getUserNameBytes() {\n            java.lang.Object ref = userName_;\n            if (ref instanceof java.lang.String) {\n                com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8((java.lang.String) ref);\n                userName_ = b;\n                return b;\n            } else {\n                return (com.google.protobuf.ByteString) ref;\n            }\n        }\n\n        public static final int PRODUCTNAME_FIELD_NUMBER = 3;\n\n        private java.lang.Object productName_;\n\n        /**\n         * <code>required string productName = 3;</code>\n         */\n        public boolean hasProductName() {\n            return ((bitField0_ & 0x00000004) == 0x00000004);\n        }\n\n        /**\n         * <code>required string productName = 3;</code>\n         */\n        public java.lang.String getProductName() {\n            java.lang.Object ref = productName_;\n            if (ref instanceof java.lang.String) {\n                return (java.lang.String) ref;\n            } else {\n                com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref;\n                java.lang.String s = bs.toStringUtf8();\n                if (bs.isValidUtf8()) {\n                    productName_ = s;\n                }\n                return s;\n            }\n        }\n\n        /**\n         * <code>required string productName = 3;</code>\n         */\n        public com.google.protobuf.ByteString getProductNameBytes() {\n            java.lang.Object ref = productName_;\n            if (ref instanceof java.lang.String) {\n                com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8((java.lang.String) ref);\n                productName_ = b;\n                return b;\n            } else {\n                return (com.google.protobuf.ByteString) ref;\n            }\n        }\n\n        public static final int ADDRESS_FIELD_NUMBER = 4;\n\n        private com.google.protobuf.LazyStringList address_;\n\n        /**\n         * <code>repeated string address = 4;</code>\n         */\n        public com.google.protobuf.ProtocolStringList getAddressList() {\n            return address_;\n        }\n\n        /**\n         * <code>repeated string address = 4;</code>\n         */\n        public int getAddressCount() {\n            return address_.size();\n        }\n\n        /**\n         * <code>repeated string address = 4;</code>\n         */\n        public java.lang.String getAddress(int index) {\n            return address_.get(index);\n        }\n\n        /**\n         * <code>repeated string address = 4;</code>\n         */\n        public com.google.protobuf.ByteString getAddressBytes(int index) {\n            return address_.getByteString(index);\n        }\n\n        private void initFields() {\n            subReqID_ = 0;\n            userName_ = \"\";\n            productName_ = \"\";\n            address_ = com.google.protobuf.LazyStringArrayList.EMPTY;\n        }\n\n        private byte memoizedIsInitialized = -1;\n\n        public final boolean isInitialized() {\n            byte isInitialized = memoizedIsInitialized;\n            if (isInitialized == 1)\n                return true;\n            if (isInitialized == 0)\n                return false;\n\n            if (!hasSubReqID()) {\n                memoizedIsInitialized = 0;\n                return false;\n            }\n            if (!hasUserName()) {\n                memoizedIsInitialized = 0;\n                return false;\n            }\n            if (!hasProductName()) {\n                memoizedIsInitialized = 0;\n                return false;\n            }\n            memoizedIsInitialized = 1;\n            return true;\n        }\n\n        public void writeTo(com.google.protobuf.CodedOutputStream output) throws java.io.IOException {\n            getSerializedSize();\n            if (((bitField0_ & 0x00000001) == 0x00000001)) {\n                output.writeInt32(1, subReqID_);\n            }\n            if (((bitField0_ & 0x00000002) == 0x00000002)) {\n                output.writeBytes(2, getUserNameBytes());\n            }\n            if (((bitField0_ & 0x00000004) == 0x00000004)) {\n                output.writeBytes(3, getProductNameBytes());\n            }\n            for (int i = 0; i < address_.size(); i++) {\n                output.writeBytes(4, address_.getByteString(i));\n            }\n            getUnknownFields().writeTo(output);\n        }\n\n        private int memoizedSerializedSize = -1;\n\n        public int getSerializedSize() {\n            int size = memoizedSerializedSize;\n            if (size != -1)\n                return size;\n\n            size = 0;\n            if (((bitField0_ & 0x00000001) == 0x00000001)) {\n                size += com.google.protobuf.CodedOutputStream.computeInt32Size(1, subReqID_);\n            }\n            if (((bitField0_ & 0x00000002) == 0x00000002)) {\n                size += com.google.protobuf.CodedOutputStream.computeBytesSize(2, getUserNameBytes());\n            }\n            if (((bitField0_ & 0x00000004) == 0x00000004)) {\n                size += com.google.protobuf.CodedOutputStream.computeBytesSize(3, getProductNameBytes());\n            }\n            {\n                int dataSize = 0;\n                for (int i = 0; i < address_.size(); i++) {\n                    dataSize += com.google.protobuf.CodedOutputStream.computeBytesSizeNoTag(address_.getByteString(i));\n                }\n                size += dataSize;\n                size += 1 * getAddressList().size();\n            }\n            size += getUnknownFields().getSerializedSize();\n            memoizedSerializedSize = size;\n            return size;\n        }\n\n        private static final long serialVersionUID = 0L;\n\n        @java.lang.Override\n        protected java.lang.Object writeReplace() throws java.io.ObjectStreamException {\n            return super.writeReplace();\n        }\n\n        public static com.lyncc.netty.codec.protobuf.SubscribeReqProto.SubscribeReq parseFrom(\n                com.google.protobuf.ByteString data) throws com.google.protobuf.InvalidProtocolBufferException {\n            return PARSER.parseFrom(data);\n        }\n\n        public static com.lyncc.netty.codec.protobuf.SubscribeReqProto.SubscribeReq parseFrom(\n                com.google.protobuf.ByteString data, com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n                throws com.google.protobuf.InvalidProtocolBufferException {\n            return PARSER.parseFrom(data, extensionRegistry);\n        }\n\n        public static com.lyncc.netty.codec.protobuf.SubscribeReqProto.SubscribeReq parseFrom(byte[] data)\n                throws com.google.protobuf.InvalidProtocolBufferException {\n            return PARSER.parseFrom(data);\n        }\n\n        public static com.lyncc.netty.codec.protobuf.SubscribeReqProto.SubscribeReq parseFrom(byte[] data,\n                com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n                throws com.google.protobuf.InvalidProtocolBufferException {\n            return PARSER.parseFrom(data, extensionRegistry);\n        }\n\n        public static com.lyncc.netty.codec.protobuf.SubscribeReqProto.SubscribeReq parseFrom(java.io.InputStream input)\n                throws java.io.IOException {\n            return PARSER.parseFrom(input);\n        }\n\n        public static com.lyncc.netty.codec.protobuf.SubscribeReqProto.SubscribeReq parseFrom(\n                java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n                throws java.io.IOException {\n            return PARSER.parseFrom(input, extensionRegistry);\n        }\n\n        public static com.lyncc.netty.codec.protobuf.SubscribeReqProto.SubscribeReq parseDelimitedFrom(\n                java.io.InputStream input) throws java.io.IOException {\n            return PARSER.parseDelimitedFrom(input);\n        }\n\n        public static com.lyncc.netty.codec.protobuf.SubscribeReqProto.SubscribeReq parseDelimitedFrom(\n                java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n                throws java.io.IOException {\n            return PARSER.parseDelimitedFrom(input, extensionRegistry);\n        }\n\n        public static com.lyncc.netty.codec.protobuf.SubscribeReqProto.SubscribeReq parseFrom(\n                com.google.protobuf.CodedInputStream input) throws java.io.IOException {\n            return PARSER.parseFrom(input);\n        }\n\n        public static com.lyncc.netty.codec.protobuf.SubscribeReqProto.SubscribeReq parseFrom(\n                com.google.protobuf.CodedInputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n                throws java.io.IOException {\n            return PARSER.parseFrom(input, extensionRegistry);\n        }\n\n        public static Builder newBuilder() {\n            return Builder.create();\n        }\n\n        public Builder newBuilderForType() {\n            return newBuilder();\n        }\n\n        public static Builder newBuilder(com.lyncc.netty.codec.protobuf.SubscribeReqProto.SubscribeReq prototype) {\n            return newBuilder().mergeFrom(prototype);\n        }\n\n        public Builder toBuilder() {\n            return newBuilder(this);\n        }\n\n        @java.lang.Override\n        protected Builder newBuilderForType(com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n            Builder builder = new Builder(parent);\n            return builder;\n        }\n\n        /**\n         * Protobuf type {@code netty.SubscribeReq}\n         */\n        public static final class Builder extends com.google.protobuf.GeneratedMessage.Builder<Builder> implements\n        // @@protoc_insertion_point(builder_implements:netty.SubscribeReq)\n                com.lyncc.netty.codec.protobuf.SubscribeReqProto.SubscribeReqOrBuilder {\n            public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() {\n                return com.lyncc.netty.codec.protobuf.SubscribeReqProto.internal_static_netty_SubscribeReq_descriptor;\n            }\n\n            protected com.google.protobuf.GeneratedMessage.FieldAccessorTable internalGetFieldAccessorTable() {\n                return com.lyncc.netty.codec.protobuf.SubscribeReqProto.internal_static_netty_SubscribeReq_fieldAccessorTable\n                        .ensureFieldAccessorsInitialized(\n                                com.lyncc.netty.codec.protobuf.SubscribeReqProto.SubscribeReq.class,\n                                com.lyncc.netty.codec.protobuf.SubscribeReqProto.SubscribeReq.Builder.class);\n            }\n\n            // Construct using\n            // com.lyncc.netty.codec.protobuf.SubscribeReqProto.SubscribeReq.newBuilder()\n            private Builder() {\n                maybeForceBuilderInitialization();\n            }\n\n            private Builder(com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n                super(parent);\n                maybeForceBuilderInitialization();\n            }\n\n            private void maybeForceBuilderInitialization() {\n                if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n                }\n            }\n\n            private static Builder create() {\n                return new Builder();\n            }\n\n            public Builder clear() {\n                super.clear();\n                subReqID_ = 0;\n                bitField0_ = (bitField0_ & ~0x00000001);\n                userName_ = \"\";\n                bitField0_ = (bitField0_ & ~0x00000002);\n                productName_ = \"\";\n                bitField0_ = (bitField0_ & ~0x00000004);\n                address_ = com.google.protobuf.LazyStringArrayList.EMPTY;\n                bitField0_ = (bitField0_ & ~0x00000008);\n                return this;\n            }\n\n            public Builder clone() {\n                return create().mergeFrom(buildPartial());\n            }\n\n            public com.google.protobuf.Descriptors.Descriptor getDescriptorForType() {\n                return com.lyncc.netty.codec.protobuf.SubscribeReqProto.internal_static_netty_SubscribeReq_descriptor;\n            }\n\n            public com.lyncc.netty.codec.protobuf.SubscribeReqProto.SubscribeReq getDefaultInstanceForType() {\n                return com.lyncc.netty.codec.protobuf.SubscribeReqProto.SubscribeReq.getDefaultInstance();\n            }\n\n            public com.lyncc.netty.codec.protobuf.SubscribeReqProto.SubscribeReq build() {\n                com.lyncc.netty.codec.protobuf.SubscribeReqProto.SubscribeReq result = buildPartial();\n                if (!result.isInitialized()) {\n                    throw newUninitializedMessageException(result);\n                }\n                return result;\n            }\n\n            public com.lyncc.netty.codec.protobuf.SubscribeReqProto.SubscribeReq buildPartial() {\n                com.lyncc.netty.codec.protobuf.SubscribeReqProto.SubscribeReq result = new com.lyncc.netty.codec.protobuf.SubscribeReqProto.SubscribeReq(\n                        this);\n                int from_bitField0_ = bitField0_;\n                int to_bitField0_ = 0;\n                if (((from_bitField0_ & 0x00000001) == 0x00000001)) {\n                    to_bitField0_ |= 0x00000001;\n                }\n                result.subReqID_ = subReqID_;\n                if (((from_bitField0_ & 0x00000002) == 0x00000002)) {\n                    to_bitField0_ |= 0x00000002;\n                }\n                result.userName_ = userName_;\n                if (((from_bitField0_ & 0x00000004) == 0x00000004)) {\n                    to_bitField0_ |= 0x00000004;\n                }\n                result.productName_ = productName_;\n                if (((bitField0_ & 0x00000008) == 0x00000008)) {\n                    address_ = address_.getUnmodifiableView();\n                    bitField0_ = (bitField0_ & ~0x00000008);\n                }\n                result.address_ = address_;\n                result.bitField0_ = to_bitField0_;\n                onBuilt();\n                return result;\n            }\n\n            public Builder mergeFrom(com.google.protobuf.Message other) {\n                if (other instanceof com.lyncc.netty.codec.protobuf.SubscribeReqProto.SubscribeReq) {\n                    return mergeFrom((com.lyncc.netty.codec.protobuf.SubscribeReqProto.SubscribeReq) other);\n                } else {\n                    super.mergeFrom(other);\n                    return this;\n                }\n            }\n\n            public Builder mergeFrom(com.lyncc.netty.codec.protobuf.SubscribeReqProto.SubscribeReq other) {\n                if (other == com.lyncc.netty.codec.protobuf.SubscribeReqProto.SubscribeReq.getDefaultInstance())\n                    return this;\n                if (other.hasSubReqID()) {\n                    setSubReqID(other.getSubReqID());\n                }\n                if (other.hasUserName()) {\n                    bitField0_ |= 0x00000002;\n                    userName_ = other.userName_;\n                    onChanged();\n                }\n                if (other.hasProductName()) {\n                    bitField0_ |= 0x00000004;\n                    productName_ = other.productName_;\n                    onChanged();\n                }\n                if (!other.address_.isEmpty()) {\n                    if (address_.isEmpty()) {\n                        address_ = other.address_;\n                        bitField0_ = (bitField0_ & ~0x00000008);\n                    } else {\n                        ensureAddressIsMutable();\n                        address_.addAll(other.address_);\n                    }\n                    onChanged();\n                }\n                this.mergeUnknownFields(other.getUnknownFields());\n                return this;\n            }\n\n            public final boolean isInitialized() {\n                if (!hasSubReqID()) {\n\n                    return false;\n                }\n                if (!hasUserName()) {\n\n                    return false;\n                }\n                if (!hasProductName()) {\n\n                    return false;\n                }\n                return true;\n            }\n\n            public Builder mergeFrom(com.google.protobuf.CodedInputStream input,\n                    com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException {\n                com.lyncc.netty.codec.protobuf.SubscribeReqProto.SubscribeReq parsedMessage = null;\n                try {\n                    parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n                } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n                    parsedMessage = (com.lyncc.netty.codec.protobuf.SubscribeReqProto.SubscribeReq) e\n                            .getUnfinishedMessage();\n                    throw e;\n                } finally {\n                    if (parsedMessage != null) {\n                        mergeFrom(parsedMessage);\n                    }\n                }\n                return this;\n            }\n\n            private int bitField0_;\n\n            private int subReqID_;\n\n            /**\n             * <code>required int32 subReqID = 1;</code>\n             */\n            public boolean hasSubReqID() {\n                return ((bitField0_ & 0x00000001) == 0x00000001);\n            }\n\n            /**\n             * <code>required int32 subReqID = 1;</code>\n             */\n            public int getSubReqID() {\n                return subReqID_;\n            }\n\n            /**\n             * <code>required int32 subReqID = 1;</code>\n             */\n            public Builder setSubReqID(int value) {\n                bitField0_ |= 0x00000001;\n                subReqID_ = value;\n                onChanged();\n                return this;\n            }\n\n            /**\n             * <code>required int32 subReqID = 1;</code>\n             */\n            public Builder clearSubReqID() {\n                bitField0_ = (bitField0_ & ~0x00000001);\n                subReqID_ = 0;\n                onChanged();\n                return this;\n            }\n\n            private java.lang.Object userName_ = \"\";\n\n            /**\n             * <code>required string userName = 2;</code>\n             */\n            public boolean hasUserName() {\n                return ((bitField0_ & 0x00000002) == 0x00000002);\n            }\n\n            /**\n             * <code>required string userName = 2;</code>\n             */\n            public java.lang.String getUserName() {\n                java.lang.Object ref = userName_;\n                if (!(ref instanceof java.lang.String)) {\n                    com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref;\n                    java.lang.String s = bs.toStringUtf8();\n                    if (bs.isValidUtf8()) {\n                        userName_ = s;\n                    }\n                    return s;\n                } else {\n                    return (java.lang.String) ref;\n                }\n            }\n\n            /**\n             * <code>required string userName = 2;</code>\n             */\n            public com.google.protobuf.ByteString getUserNameBytes() {\n                java.lang.Object ref = userName_;\n                if (ref instanceof String) {\n                    com.google.protobuf.ByteString b = com.google.protobuf.ByteString\n                            .copyFromUtf8((java.lang.String) ref);\n                    userName_ = b;\n                    return b;\n                } else {\n                    return (com.google.protobuf.ByteString) ref;\n                }\n            }\n\n            /**\n             * <code>required string userName = 2;</code>\n             */\n            public Builder setUserName(java.lang.String value) {\n                if (value == null) {\n                    throw new NullPointerException();\n                }\n                bitField0_ |= 0x00000002;\n                userName_ = value;\n                onChanged();\n                return this;\n            }\n\n            /**\n             * <code>required string userName = 2;</code>\n             */\n            public Builder clearUserName() {\n                bitField0_ = (bitField0_ & ~0x00000002);\n                userName_ = getDefaultInstance().getUserName();\n                onChanged();\n                return this;\n            }\n\n            /**\n             * <code>required string userName = 2;</code>\n             */\n            public Builder setUserNameBytes(com.google.protobuf.ByteString value) {\n                if (value == null) {\n                    throw new NullPointerException();\n                }\n                bitField0_ |= 0x00000002;\n                userName_ = value;\n                onChanged();\n                return this;\n            }\n\n            private java.lang.Object productName_ = \"\";\n\n            /**\n             * <code>required string productName = 3;</code>\n             */\n            public boolean hasProductName() {\n                return ((bitField0_ & 0x00000004) == 0x00000004);\n            }\n\n            /**\n             * <code>required string productName = 3;</code>\n             */\n            public java.lang.String getProductName() {\n                java.lang.Object ref = productName_;\n                if (!(ref instanceof java.lang.String)) {\n                    com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref;\n                    java.lang.String s = bs.toStringUtf8();\n                    if (bs.isValidUtf8()) {\n                        productName_ = s;\n                    }\n                    return s;\n                } else {\n                    return (java.lang.String) ref;\n                }\n            }\n\n            /**\n             * <code>required string productName = 3;</code>\n             */\n            public com.google.protobuf.ByteString getProductNameBytes() {\n                java.lang.Object ref = productName_;\n                if (ref instanceof String) {\n                    com.google.protobuf.ByteString b = com.google.protobuf.ByteString\n                            .copyFromUtf8((java.lang.String) ref);\n                    productName_ = b;\n                    return b;\n                } else {\n                    return (com.google.protobuf.ByteString) ref;\n                }\n            }\n\n            /**\n             * <code>required string productName = 3;</code>\n             */\n            public Builder setProductName(java.lang.String value) {\n                if (value == null) {\n                    throw new NullPointerException();\n                }\n                bitField0_ |= 0x00000004;\n                productName_ = value;\n                onChanged();\n                return this;\n            }\n\n            /**\n             * <code>required string productName = 3;</code>\n             */\n            public Builder clearProductName() {\n                bitField0_ = (bitField0_ & ~0x00000004);\n                productName_ = getDefaultInstance().getProductName();\n                onChanged();\n                return this;\n            }\n\n            /**\n             * <code>required string productName = 3;</code>\n             */\n            public Builder setProductNameBytes(com.google.protobuf.ByteString value) {\n                if (value == null) {\n                    throw new NullPointerException();\n                }\n                bitField0_ |= 0x00000004;\n                productName_ = value;\n                onChanged();\n                return this;\n            }\n\n            private com.google.protobuf.LazyStringList address_ = com.google.protobuf.LazyStringArrayList.EMPTY;\n\n            private void ensureAddressIsMutable() {\n                if (!((bitField0_ & 0x00000008) == 0x00000008)) {\n                    address_ = new com.google.protobuf.LazyStringArrayList(address_);\n                    bitField0_ |= 0x00000008;\n                }\n            }\n\n            /**\n             * <code>repeated string address = 4;</code>\n             */\n            public com.google.protobuf.ProtocolStringList getAddressList() {\n                return address_.getUnmodifiableView();\n            }\n\n            /**\n             * <code>repeated string address = 4;</code>\n             */\n            public int getAddressCount() {\n                return address_.size();\n            }\n\n            /**\n             * <code>repeated string address = 4;</code>\n             */\n            public java.lang.String getAddress(int index) {\n                return address_.get(index);\n            }\n\n            /**\n             * <code>repeated string address = 4;</code>\n             */\n            public com.google.protobuf.ByteString getAddressBytes(int index) {\n                return address_.getByteString(index);\n            }\n\n            /**\n             * <code>repeated string address = 4;</code>\n             */\n            public Builder setAddress(int index, java.lang.String value) {\n                if (value == null) {\n                    throw new NullPointerException();\n                }\n                ensureAddressIsMutable();\n                address_.set(index, value);\n                onChanged();\n                return this;\n            }\n\n            /**\n             * <code>repeated string address = 4;</code>\n             */\n            public Builder addAddress(java.lang.String value) {\n                if (value == null) {\n                    throw new NullPointerException();\n                }\n                ensureAddressIsMutable();\n                address_.add(value);\n                onChanged();\n                return this;\n            }\n\n            /**\n             * <code>repeated string address = 4;</code>\n             */\n            public Builder addAllAddress(java.lang.Iterable<java.lang.String> values) {\n                ensureAddressIsMutable();\n                com.google.protobuf.AbstractMessageLite.Builder.addAll(values, address_);\n                onChanged();\n                return this;\n            }\n\n            /**\n             * <code>repeated string address = 4;</code>\n             */\n            public Builder clearAddress() {\n                address_ = com.google.protobuf.LazyStringArrayList.EMPTY;\n                bitField0_ = (bitField0_ & ~0x00000008);\n                onChanged();\n                return this;\n            }\n\n            /**\n             * <code>repeated string address = 4;</code>\n             */\n            public Builder addAddressBytes(com.google.protobuf.ByteString value) {\n                if (value == null) {\n                    throw new NullPointerException();\n                }\n                ensureAddressIsMutable();\n                address_.add(value);\n                onChanged();\n                return this;\n            }\n\n            // @@protoc_insertion_point(builder_scope:netty.SubscribeReq)\n        }\n\n        static {\n            defaultInstance = new SubscribeReq(true);\n            defaultInstance.initFields();\n        }\n\n        // @@protoc_insertion_point(class_scope:netty.SubscribeReq)\n    }\n\n    private static final com.google.protobuf.Descriptors.Descriptor internal_static_netty_SubscribeReq_descriptor;\n\n    private static com.google.protobuf.GeneratedMessage.FieldAccessorTable internal_static_netty_SubscribeReq_fieldAccessorTable;\n\n    public static com.google.protobuf.Descriptors.FileDescriptor getDescriptor() {\n        return descriptor;\n    }\n\n    private static com.google.protobuf.Descriptors.FileDescriptor descriptor;\n    static {\n        java.lang.String[] descriptorData = { \"\\n\\022SubscribeReq.proto\\022\\005netty\\\"X\\n\\014Subscribe\"\n                + \"Req\\022\\020\\n\\010subReqID\\030\\001 \\002(\\005\\022\\020\\n\\010userName\\030\\002 \\002(\\t\\022\"\n                + \"\\023\\n\\013productName\\030\\003 \\002(\\t\\022\\017\\n\\007address\\030\\004 \\003(\\tB3\\n\"\n                + \"\\036com.lyncc.netty.codec.protobufB\\021Subscri\" + \"beReqProto\" };\n        com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner = new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() {\n            public com.google.protobuf.ExtensionRegistry assignDescriptors(\n                    com.google.protobuf.Descriptors.FileDescriptor root) {\n                descriptor = root;\n                return null;\n            }\n        };\n        com.google.protobuf.Descriptors.FileDescriptor.internalBuildGeneratedFileFrom(descriptorData,\n                new com.google.protobuf.Descriptors.FileDescriptor[] {}, assigner);\n        internal_static_netty_SubscribeReq_descriptor = getDescriptor().getMessageTypes().get(0);\n        internal_static_netty_SubscribeReq_fieldAccessorTable = new com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n                internal_static_netty_SubscribeReq_descriptor, new java.lang.String[] { \"SubReqID\", \"UserName\",\n                        \"ProductName\", \"Address\", });\n    }\n\n    // @@protoc_insertion_point(outer_class_scope)\n}\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/codec/protobuf/SubscribeResp.proto",
    "content": "package netty;  \r\noption java_package = \"com.lyncc.netty.codec.protobuf\";  \r\noption java_outer_classname = \"SubscribeRespProto\";  \r\n  \r\nmessage SubscribeReq{  \r\n    required int32 subReqID = 1;  \r\n    required int23 respCode = 2;  \r\n    required string desc = 3;  \r\n} "
  },
  {
    "path": "src/main/java/com/lyncc/netty/codec/protobuf/SubscribeRespProto.java",
    "content": "// Generated by the protocol buffer compiler.  DO NOT EDIT!\n// source: SubscribeResp.proto\n\npackage com.lyncc.netty.codec.protobuf;\n\npublic final class SubscribeRespProto {\n  private SubscribeRespProto() {}\n  public static void registerAllExtensions(\n      com.google.protobuf.ExtensionRegistry registry) {\n  }\n  public interface SubscribeRespOrBuilder extends\n      // @@protoc_insertion_point(interface_extends:netty.SubscribeResp)\n      com.google.protobuf.MessageOrBuilder {\n\n    /**\n     * <code>required int32 subReqID = 1;</code>\n     */\n    boolean hasSubReqID();\n    /**\n     * <code>required int32 subReqID = 1;</code>\n     */\n    int getSubReqID();\n\n    /**\n     * <code>required int32 respCode = 2;</code>\n     */\n    boolean hasRespCode();\n    /**\n     * <code>required int32 respCode = 2;</code>\n     */\n    int getRespCode();\n\n    /**\n     * <code>required string desc = 3;</code>\n     */\n    boolean hasDesc();\n    /**\n     * <code>required string desc = 3;</code>\n     */\n    java.lang.String getDesc();\n    /**\n     * <code>required string desc = 3;</code>\n     */\n    com.google.protobuf.ByteString\n        getDescBytes();\n  }\n  /**\n   * Protobuf type {@code netty.SubscribeResp}\n   */\n  public static final class SubscribeResp extends\n      com.google.protobuf.GeneratedMessage implements\n      // @@protoc_insertion_point(message_implements:netty.SubscribeResp)\n      SubscribeRespOrBuilder {\n    // Use SubscribeResp.newBuilder() to construct.\n    private SubscribeResp(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private SubscribeResp(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final SubscribeResp defaultInstance;\n    public static SubscribeResp getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public SubscribeResp getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private SubscribeResp(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 8: {\n              bitField0_ |= 0x00000001;\n              subReqID_ = input.readInt32();\n              break;\n            }\n            case 16: {\n              bitField0_ |= 0x00000002;\n              respCode_ = input.readInt32();\n              break;\n            }\n            case 26: {\n              com.google.protobuf.ByteString bs = input.readBytes();\n              bitField0_ |= 0x00000004;\n              desc_ = bs;\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return com.lyncc.netty.codec.protobuf.SubscribeRespProto.internal_static_netty_SubscribeResp_descriptor;\n    }\n\n    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return com.lyncc.netty.codec.protobuf.SubscribeRespProto.internal_static_netty_SubscribeResp_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              com.lyncc.netty.codec.protobuf.SubscribeRespProto.SubscribeResp.class, com.lyncc.netty.codec.protobuf.SubscribeRespProto.SubscribeResp.Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<SubscribeResp> PARSER =\n        new com.google.protobuf.AbstractParser<SubscribeResp>() {\n      public SubscribeResp parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new SubscribeResp(input, extensionRegistry);\n      }\n    };\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<SubscribeResp> getParserForType() {\n      return PARSER;\n    }\n\n    private int bitField0_;\n    public static final int SUBREQID_FIELD_NUMBER = 1;\n    private int subReqID_;\n    /**\n     * <code>required int32 subReqID = 1;</code>\n     */\n    public boolean hasSubReqID() {\n      return ((bitField0_ & 0x00000001) == 0x00000001);\n    }\n    /**\n     * <code>required int32 subReqID = 1;</code>\n     */\n    public int getSubReqID() {\n      return subReqID_;\n    }\n\n    public static final int RESPCODE_FIELD_NUMBER = 2;\n    private int respCode_;\n    /**\n     * <code>required int32 respCode = 2;</code>\n     */\n    public boolean hasRespCode() {\n      return ((bitField0_ & 0x00000002) == 0x00000002);\n    }\n    /**\n     * <code>required int32 respCode = 2;</code>\n     */\n    public int getRespCode() {\n      return respCode_;\n    }\n\n    public static final int DESC_FIELD_NUMBER = 3;\n    private java.lang.Object desc_;\n    /**\n     * <code>required string desc = 3;</code>\n     */\n    public boolean hasDesc() {\n      return ((bitField0_ & 0x00000004) == 0x00000004);\n    }\n    /**\n     * <code>required string desc = 3;</code>\n     */\n    public java.lang.String getDesc() {\n      java.lang.Object ref = desc_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          desc_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>required string desc = 3;</code>\n     */\n    public com.google.protobuf.ByteString\n        getDescBytes() {\n      java.lang.Object ref = desc_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        desc_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    private void initFields() {\n      subReqID_ = 0;\n      respCode_ = 0;\n      desc_ = \"\";\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized == 1) return true;\n      if (isInitialized == 0) return false;\n\n      if (!hasSubReqID()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      if (!hasRespCode()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      if (!hasDesc()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        output.writeInt32(1, subReqID_);\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        output.writeInt32(2, respCode_);\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        output.writeBytes(3, getDescBytes());\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(1, subReqID_);\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(2, respCode_);\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(3, getDescBytes());\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @java.lang.Override\n    protected java.lang.Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static com.lyncc.netty.codec.protobuf.SubscribeRespProto.SubscribeResp parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static com.lyncc.netty.codec.protobuf.SubscribeRespProto.SubscribeResp parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static com.lyncc.netty.codec.protobuf.SubscribeRespProto.SubscribeResp parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static com.lyncc.netty.codec.protobuf.SubscribeRespProto.SubscribeResp parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static com.lyncc.netty.codec.protobuf.SubscribeRespProto.SubscribeResp parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static com.lyncc.netty.codec.protobuf.SubscribeRespProto.SubscribeResp parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static com.lyncc.netty.codec.protobuf.SubscribeRespProto.SubscribeResp parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static com.lyncc.netty.codec.protobuf.SubscribeRespProto.SubscribeResp parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static com.lyncc.netty.codec.protobuf.SubscribeRespProto.SubscribeResp parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static com.lyncc.netty.codec.protobuf.SubscribeRespProto.SubscribeResp parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(com.lyncc.netty.codec.protobuf.SubscribeRespProto.SubscribeResp prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code netty.SubscribeResp}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder> implements\n        // @@protoc_insertion_point(builder_implements:netty.SubscribeResp)\n        com.lyncc.netty.codec.protobuf.SubscribeRespProto.SubscribeRespOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return com.lyncc.netty.codec.protobuf.SubscribeRespProto.internal_static_netty_SubscribeResp_descriptor;\n      }\n\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return com.lyncc.netty.codec.protobuf.SubscribeRespProto.internal_static_netty_SubscribeResp_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                com.lyncc.netty.codec.protobuf.SubscribeRespProto.SubscribeResp.class, com.lyncc.netty.codec.protobuf.SubscribeRespProto.SubscribeResp.Builder.class);\n      }\n\n      // Construct using com.lyncc.netty.codec.protobuf.SubscribeRespProto.SubscribeResp.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        subReqID_ = 0;\n        bitField0_ = (bitField0_ & ~0x00000001);\n        respCode_ = 0;\n        bitField0_ = (bitField0_ & ~0x00000002);\n        desc_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000004);\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return com.lyncc.netty.codec.protobuf.SubscribeRespProto.internal_static_netty_SubscribeResp_descriptor;\n      }\n\n      public com.lyncc.netty.codec.protobuf.SubscribeRespProto.SubscribeResp getDefaultInstanceForType() {\n        return com.lyncc.netty.codec.protobuf.SubscribeRespProto.SubscribeResp.getDefaultInstance();\n      }\n\n      public com.lyncc.netty.codec.protobuf.SubscribeRespProto.SubscribeResp build() {\n        com.lyncc.netty.codec.protobuf.SubscribeRespProto.SubscribeResp result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public com.lyncc.netty.codec.protobuf.SubscribeRespProto.SubscribeResp buildPartial() {\n        com.lyncc.netty.codec.protobuf.SubscribeRespProto.SubscribeResp result = new com.lyncc.netty.codec.protobuf.SubscribeRespProto.SubscribeResp(this);\n        int from_bitField0_ = bitField0_;\n        int to_bitField0_ = 0;\n        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {\n          to_bitField0_ |= 0x00000001;\n        }\n        result.subReqID_ = subReqID_;\n        if (((from_bitField0_ & 0x00000002) == 0x00000002)) {\n          to_bitField0_ |= 0x00000002;\n        }\n        result.respCode_ = respCode_;\n        if (((from_bitField0_ & 0x00000004) == 0x00000004)) {\n          to_bitField0_ |= 0x00000004;\n        }\n        result.desc_ = desc_;\n        result.bitField0_ = to_bitField0_;\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof com.lyncc.netty.codec.protobuf.SubscribeRespProto.SubscribeResp) {\n          return mergeFrom((com.lyncc.netty.codec.protobuf.SubscribeRespProto.SubscribeResp)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(com.lyncc.netty.codec.protobuf.SubscribeRespProto.SubscribeResp other) {\n        if (other == com.lyncc.netty.codec.protobuf.SubscribeRespProto.SubscribeResp.getDefaultInstance()) return this;\n        if (other.hasSubReqID()) {\n          setSubReqID(other.getSubReqID());\n        }\n        if (other.hasRespCode()) {\n          setRespCode(other.getRespCode());\n        }\n        if (other.hasDesc()) {\n          bitField0_ |= 0x00000004;\n          desc_ = other.desc_;\n          onChanged();\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        if (!hasSubReqID()) {\n          \n          return false;\n        }\n        if (!hasRespCode()) {\n          \n          return false;\n        }\n        if (!hasDesc()) {\n          \n          return false;\n        }\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        com.lyncc.netty.codec.protobuf.SubscribeRespProto.SubscribeResp parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (com.lyncc.netty.codec.protobuf.SubscribeRespProto.SubscribeResp) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      private int subReqID_ ;\n      /**\n       * <code>required int32 subReqID = 1;</code>\n       */\n      public boolean hasSubReqID() {\n        return ((bitField0_ & 0x00000001) == 0x00000001);\n      }\n      /**\n       * <code>required int32 subReqID = 1;</code>\n       */\n      public int getSubReqID() {\n        return subReqID_;\n      }\n      /**\n       * <code>required int32 subReqID = 1;</code>\n       */\n      public Builder setSubReqID(int value) {\n        bitField0_ |= 0x00000001;\n        subReqID_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required int32 subReqID = 1;</code>\n       */\n      public Builder clearSubReqID() {\n        bitField0_ = (bitField0_ & ~0x00000001);\n        subReqID_ = 0;\n        onChanged();\n        return this;\n      }\n\n      private int respCode_ ;\n      /**\n       * <code>required int32 respCode = 2;</code>\n       */\n      public boolean hasRespCode() {\n        return ((bitField0_ & 0x00000002) == 0x00000002);\n      }\n      /**\n       * <code>required int32 respCode = 2;</code>\n       */\n      public int getRespCode() {\n        return respCode_;\n      }\n      /**\n       * <code>required int32 respCode = 2;</code>\n       */\n      public Builder setRespCode(int value) {\n        bitField0_ |= 0x00000002;\n        respCode_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required int32 respCode = 2;</code>\n       */\n      public Builder clearRespCode() {\n        bitField0_ = (bitField0_ & ~0x00000002);\n        respCode_ = 0;\n        onChanged();\n        return this;\n      }\n\n      private java.lang.Object desc_ = \"\";\n      /**\n       * <code>required string desc = 3;</code>\n       */\n      public boolean hasDesc() {\n        return ((bitField0_ & 0x00000004) == 0x00000004);\n      }\n      /**\n       * <code>required string desc = 3;</code>\n       */\n      public java.lang.String getDesc() {\n        java.lang.Object ref = desc_;\n        if (!(ref instanceof java.lang.String)) {\n          com.google.protobuf.ByteString bs =\n              (com.google.protobuf.ByteString) ref;\n          java.lang.String s = bs.toStringUtf8();\n          if (bs.isValidUtf8()) {\n            desc_ = s;\n          }\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>required string desc = 3;</code>\n       */\n      public com.google.protobuf.ByteString\n          getDescBytes() {\n        java.lang.Object ref = desc_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          desc_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>required string desc = 3;</code>\n       */\n      public Builder setDesc(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000004;\n        desc_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string desc = 3;</code>\n       */\n      public Builder clearDesc() {\n        bitField0_ = (bitField0_ & ~0x00000004);\n        desc_ = getDefaultInstance().getDesc();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string desc = 3;</code>\n       */\n      public Builder setDescBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000004;\n        desc_ = value;\n        onChanged();\n        return this;\n      }\n\n      // @@protoc_insertion_point(builder_scope:netty.SubscribeResp)\n    }\n\n    static {\n      defaultInstance = new SubscribeResp(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:netty.SubscribeResp)\n  }\n\n  private static final com.google.protobuf.Descriptors.Descriptor\n    internal_static_netty_SubscribeResp_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_netty_SubscribeResp_fieldAccessorTable;\n\n  public static com.google.protobuf.Descriptors.FileDescriptor\n      getDescriptor() {\n    return descriptor;\n  }\n  private static com.google.protobuf.Descriptors.FileDescriptor\n      descriptor;\n  static {\n    java.lang.String[] descriptorData = {\n      \"\\n\\023SubscribeResp.proto\\022\\005netty\\\"A\\n\\rSubscrib\" +\n      \"eResp\\022\\020\\n\\010subReqID\\030\\001 \\002(\\005\\022\\020\\n\\010respCode\\030\\002 \\002(\" +\n      \"\\005\\022\\014\\n\\004desc\\030\\003 \\002(\\tB4\\n\\036com.lyncc.netty.codec\" +\n      \".protobufB\\022SubscribeRespProto\"\n    };\n    com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =\n        new com.google.protobuf.Descriptors.FileDescriptor.    InternalDescriptorAssigner() {\n          public com.google.protobuf.ExtensionRegistry assignDescriptors(\n              com.google.protobuf.Descriptors.FileDescriptor root) {\n            descriptor = root;\n            return null;\n          }\n        };\n    com.google.protobuf.Descriptors.FileDescriptor\n      .internalBuildGeneratedFileFrom(descriptorData,\n        new com.google.protobuf.Descriptors.FileDescriptor[] {\n        }, assigner);\n    internal_static_netty_SubscribeResp_descriptor =\n      getDescriptor().getMessageTypes().get(0);\n    internal_static_netty_SubscribeResp_fieldAccessorTable = new\n      com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n        internal_static_netty_SubscribeResp_descriptor,\n        new java.lang.String[] { \"SubReqID\", \"RespCode\", \"Desc\", });\n  }\n\n  // @@protoc_insertion_point(outer_class_scope)\n}\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/codec/protobuf/TestSubscribeReqProto.java",
    "content": "package com.lyncc.netty.codec.protobuf;\r\n\r\nimport java.util.ArrayList;\r\nimport java.util.List;\r\n\r\nimport com.google.protobuf.InvalidProtocolBufferException;\r\n\r\npublic class TestSubscribeReqProto {\r\n\r\n    private static byte[] encode(SubscribeReqProto.SubscribeReq req) {\r\n        return req.toByteArray();\r\n    }\r\n\r\n    private static SubscribeReqProto.SubscribeReq decode(byte[] body) throws InvalidProtocolBufferException {\r\n        return SubscribeReqProto.SubscribeReq.parseFrom(body);\r\n    }\r\n\r\n    private static SubscribeReqProto.SubscribeReq createSubscribeReq() {\r\n        SubscribeReqProto.SubscribeReq.Builder builder = SubscribeReqProto.SubscribeReq.newBuilder();\r\n        builder.setSubReqID(1);\r\n        builder.setUserName(\"Lilinfeng\");\r\n        builder.setProductName(\"Netty Book\");\r\n        List<String> address = new ArrayList<String>();\r\n        address.add(\"NanJing YuHuaTai\");\r\n        address.add(\"BeiJing LiuLiChang\");\r\n        address.add(\"ShenZhen HongShuLin\");\r\n        builder.addAllAddress(address);\r\n        return builder.build();\r\n    }\r\n\r\n    /**\r\n     * @param args\r\n     * @throws InvalidProtocolBufferException\r\n     */\r\n    public static void main(String[] args) throws InvalidProtocolBufferException {\r\n        SubscribeReqProto.SubscribeReq req = createSubscribeReq();\r\n        System.out.println(\"Before encode : \" + req.toString());\r\n        SubscribeReqProto.SubscribeReq req2 = decode(encode(req));\r\n        System.out.println(\"After decode : \" + req.toString());\r\n        System.out.println(\"Assert equal : --> \" + req2.equals(req));\r\n\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/codec/protobuf/demo/ProtoBufClient.java",
    "content": "package com.lyncc.netty.codec.protobuf.demo;\r\n\r\nimport io.netty.bootstrap.Bootstrap;\r\nimport io.netty.channel.ChannelFuture;\r\nimport io.netty.channel.ChannelInitializer;\r\nimport io.netty.channel.ChannelOption;\r\nimport io.netty.channel.EventLoopGroup;\r\nimport io.netty.channel.nio.NioEventLoopGroup;\r\nimport io.netty.channel.socket.SocketChannel;\r\nimport io.netty.channel.socket.nio.NioSocketChannel;\r\nimport io.netty.handler.codec.protobuf.ProtobufEncoder;\r\nimport io.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender;\r\n\r\npublic class ProtoBufClient {\r\n    \r\n    public void connect(int port, String host) throws Exception {\r\n        EventLoopGroup group = new NioEventLoopGroup();\r\n        try {\r\n            Bootstrap b = new Bootstrap();\r\n            b.group(group).channel(NioSocketChannel.class).option(ChannelOption.TCP_NODELAY, true)\r\n                    .handler(new ChannelInitializer<SocketChannel>() {\r\n                        @Override\r\n                        public void initChannel(SocketChannel ch) throws Exception {\r\n                            ch.pipeline().addLast(new ProtobufVarint32LengthFieldPrepender());\r\n                            ch.pipeline().addLast(new ProtobufEncoder());\r\n                            ch.pipeline().addLast(new ProtoBufClientHandler());\r\n                        }\r\n                    });\r\n\r\n            ChannelFuture f = b.connect(host, port).sync();\r\n\r\n            f.channel().closeFuture().sync();\r\n        } finally {\r\n            group.shutdownGracefully();\r\n        }\r\n    }\r\n\r\n    /**\r\n     * @param args\r\n     * @throws Exception\r\n     */\r\n    public static void main(String[] args) throws Exception {\r\n        int port = 8080;\r\n        if (args != null && args.length > 0) {\r\n            try {\r\n                port = Integer.valueOf(args[0]);\r\n            } catch (NumberFormatException e) {\r\n                // 采用默认值\r\n            }\r\n        }\r\n        new ProtoBufClient().connect(port, \"127.0.0.1\");\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/codec/protobuf/demo/ProtoBufClientHandler.java",
    "content": "package com.lyncc.netty.codec.protobuf.demo;\r\n\r\nimport io.netty.channel.ChannelHandlerContext;\r\nimport io.netty.channel.ChannelInboundHandlerAdapter;\r\n\r\nimport java.util.ArrayList;\r\nimport java.util.List;\r\n\r\nimport com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.Car;\r\nimport com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.CarType;\r\n\r\npublic class ProtoBufClientHandler extends ChannelInboundHandlerAdapter {\r\n    \r\n    @Override\r\n    public void channelActive(ChannelHandlerContext ctx) {\r\n        System.out.println(\"=======================================\");\r\n        RichManProto.RichMan.Builder builder = RichManProto.RichMan.newBuilder();\r\n        builder.setName(\"王思聪\");\r\n        builder.setId(1);\r\n        builder.setEmail(\"wsc@163.com\");\r\n        \r\n        List<RichManProto.RichMan.Car> cars = new ArrayList<RichManProto.RichMan.Car>();\r\n        Car car1 = RichManProto.RichMan.Car.newBuilder().setName(\"上海大众超跑\").setType(CarType.DASAUTO).build();\r\n        Car car2 = RichManProto.RichMan.Car.newBuilder().setName(\"Aventador\").setType(CarType.LAMBORGHINI).build();\r\n        Car car3 = RichManProto.RichMan.Car.newBuilder().setName(\"奔驰SLS级AMG\").setType(CarType.BENZ).build();\r\n        \r\n        cars.add(car1);\r\n        cars.add(car2);\r\n        cars.add(car3);\r\n        \r\n        builder.addAllCars(cars);\r\n        ctx.writeAndFlush(builder.build());\r\n    }\r\n\r\n\r\n    @Override\r\n    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {\r\n        cause.printStackTrace();\r\n        ctx.close();\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/codec/protobuf/demo/ProtoBufServer.java",
    "content": "package com.lyncc.netty.codec.protobuf.demo;\r\n\r\nimport io.netty.bootstrap.ServerBootstrap;\r\nimport io.netty.channel.ChannelFuture;\r\nimport io.netty.channel.ChannelInitializer;\r\nimport io.netty.channel.ChannelOption;\r\nimport io.netty.channel.EventLoopGroup;\r\nimport io.netty.channel.nio.NioEventLoopGroup;\r\nimport io.netty.channel.socket.SocketChannel;\r\nimport io.netty.channel.socket.nio.NioServerSocketChannel;\r\nimport io.netty.handler.codec.protobuf.ProtobufDecoder;\r\nimport io.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder;\r\nimport io.netty.handler.logging.LogLevel;\r\nimport io.netty.handler.logging.LoggingHandler;\r\n\r\npublic class ProtoBufServer {\r\n    \r\n    public void bind(int port) throws Exception {\r\n        // 配置服务端的NIO线程组\r\n        EventLoopGroup bossGroup = new NioEventLoopGroup();\r\n        EventLoopGroup workerGroup = new NioEventLoopGroup();\r\n        try {\r\n            ServerBootstrap b = new ServerBootstrap();\r\n            b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).option(ChannelOption.SO_BACKLOG, 100)\r\n                    .handler(new LoggingHandler(LogLevel.INFO)).childHandler(new ChannelInitializer<SocketChannel>() {\r\n                        @Override\r\n                        public void initChannel(SocketChannel ch) {\r\n                            ch.pipeline().addLast(new ProtobufVarint32FrameDecoder());\r\n                            ch.pipeline().addLast(new ProtobufDecoder(RichManProto.RichMan.getDefaultInstance()));\r\n                            ch.pipeline().addLast(new ProtoBufServerHandler());\r\n                        }\r\n                    });\r\n\r\n            // 绑定端口，同步等待成功\r\n            ChannelFuture f = b.bind(port).sync();\r\n\r\n            System.out.println(\"init start\");\r\n            // 等待服务端监听端口关闭\r\n            f.channel().closeFuture().sync();\r\n        } finally {\r\n            // 优雅退出，释放线程池资源\r\n            bossGroup.shutdownGracefully();\r\n            workerGroup.shutdownGracefully();\r\n        }\r\n    }\r\n\r\n    public static void main(String[] args) throws Exception {\r\n        int port = 8080;\r\n        if (args != null && args.length > 0) {\r\n            try {\r\n                port = Integer.valueOf(args[0]);\r\n            } catch (NumberFormatException e) {\r\n                // 采用默认值\r\n            }\r\n        }\r\n        new ProtoBufServer().bind(port);\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/codec/protobuf/demo/ProtoBufServerHandler.java",
    "content": "package com.lyncc.netty.codec.protobuf.demo;\r\n\r\nimport io.netty.channel.ChannelHandlerContext;\r\nimport io.netty.channel.ChannelInboundHandlerAdapter;\r\n\r\nimport java.util.List;\r\n\r\nimport com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.Car;\r\n\r\npublic class ProtoBufServerHandler extends ChannelInboundHandlerAdapter {\r\n    \r\n    @Override\r\n    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {\r\n        RichManProto.RichMan req = (RichManProto.RichMan) msg;\r\n        System.out.println(req.getName()+\"他有\"+req.getCarsCount()+\"量车\");\r\n        List<Car> lists = req.getCarsList();\r\n        if(null != lists) {\r\n            \r\n            for(Car car : lists){\r\n                System.out.println(car.getName());\r\n            }\r\n        }\r\n    }\r\n\r\n\r\n    @Override\r\n    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {\r\n        cause.printStackTrace();\r\n        ctx.close(); \r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/codec/protobuf/demo/RichMan.proto",
    "content": "package netty;\r\n\r\noption java_package = \"com.lyncc.netty.codec.protobuf.demo\";\r\noption java_outer_classname = \"RichManProto\";\r\n\r\nmessage RichMan {\r\n\r\n   required int32 id = 1;\r\n   required string name = 2;\r\n   optional string email = 3;\r\n   \r\n   enum CarType {\r\n     AUDI = 0;\r\n     BENZ = 1;\r\n     LAMBORGHINI = 2;\r\n     DASAUTO = 3;\r\n   }\r\n   \r\n   message Car {\r\n      required string name = 1;\r\n      optional CarType type = 2 [default = BENZ];\r\n   }\r\n   \r\n   repeated Car cars = 4;\r\n   \r\n}"
  },
  {
    "path": "src/main/java/com/lyncc/netty/codec/protobuf/demo/RichManProto.java",
    "content": "// Generated by the protocol buffer compiler.  DO NOT EDIT!\n// source: RichMan.proto\n\npackage com.lyncc.netty.codec.protobuf.demo;\n\npublic final class RichManProto {\n    private RichManProto() {\n    }\n\n    public static void registerAllExtensions(com.google.protobuf.ExtensionRegistry registry) {\n    }\n\n    public interface RichManOrBuilder extends\n    // @@protoc_insertion_point(interface_extends:netty.RichMan)\n            com.google.protobuf.MessageOrBuilder {\n\n        /**\n         * <code>required int32 id = 1;</code>\n         */\n        boolean hasId();\n\n        /**\n         * <code>required int32 id = 1;</code>\n         */\n        int getId();\n\n        /**\n         * <code>required string name = 2;</code>\n         */\n        boolean hasName();\n\n        /**\n         * <code>required string name = 2;</code>\n         */\n        java.lang.String getName();\n\n        /**\n         * <code>required string name = 2;</code>\n         */\n        com.google.protobuf.ByteString getNameBytes();\n\n        /**\n         * <code>optional string email = 3;</code>\n         */\n        boolean hasEmail();\n\n        /**\n         * <code>optional string email = 3;</code>\n         */\n        java.lang.String getEmail();\n\n        /**\n         * <code>optional string email = 3;</code>\n         */\n        com.google.protobuf.ByteString getEmailBytes();\n\n        /**\n         * <code>repeated .netty.RichMan.Car cars = 4;</code>\n         */\n        java.util.List<com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.Car> getCarsList();\n\n        /**\n         * <code>repeated .netty.RichMan.Car cars = 4;</code>\n         */\n        com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.Car getCars(int index);\n\n        /**\n         * <code>repeated .netty.RichMan.Car cars = 4;</code>\n         */\n        int getCarsCount();\n\n        /**\n         * <code>repeated .netty.RichMan.Car cars = 4;</code>\n         */\n        java.util.List<? extends com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.CarOrBuilder> getCarsOrBuilderList();\n\n        /**\n         * <code>repeated .netty.RichMan.Car cars = 4;</code>\n         */\n        com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.CarOrBuilder getCarsOrBuilder(int index);\n    }\n\n    /**\n     * Protobuf type {@code netty.RichMan}\n     */\n    public static final class RichMan extends com.google.protobuf.GeneratedMessage implements\n    // @@protoc_insertion_point(message_implements:netty.RichMan)\n            RichManOrBuilder {\n        // Use RichMan.newBuilder() to construct.\n        private RichMan(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n            super(builder);\n            this.unknownFields = builder.getUnknownFields();\n        }\n\n        private RichMan(boolean noInit) {\n            this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance();\n        }\n\n        private static final RichMan defaultInstance;\n\n        public static RichMan getDefaultInstance() {\n            return defaultInstance;\n        }\n\n        public RichMan getDefaultInstanceForType() {\n            return defaultInstance;\n        }\n\n        private final com.google.protobuf.UnknownFieldSet unknownFields;\n\n        @java.lang.Override\n        public final com.google.protobuf.UnknownFieldSet getUnknownFields() {\n            return this.unknownFields;\n        }\n\n        private RichMan(com.google.protobuf.CodedInputStream input,\n                com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n                throws com.google.protobuf.InvalidProtocolBufferException {\n            initFields();\n            int mutable_bitField0_ = 0;\n            com.google.protobuf.UnknownFieldSet.Builder unknownFields = com.google.protobuf.UnknownFieldSet\n                    .newBuilder();\n            try {\n                boolean done = false;\n                while (!done) {\n                    int tag = input.readTag();\n                    switch (tag) {\n                    case 0:\n                        done = true;\n                        break;\n                    default: {\n                        if (!parseUnknownField(input, unknownFields, extensionRegistry, tag)) {\n                            done = true;\n                        }\n                        break;\n                    }\n                    case 8: {\n                        bitField0_ |= 0x00000001;\n                        id_ = input.readInt32();\n                        break;\n                    }\n                    case 18: {\n                        com.google.protobuf.ByteString bs = input.readBytes();\n                        bitField0_ |= 0x00000002;\n                        name_ = bs;\n                        break;\n                    }\n                    case 26: {\n                        com.google.protobuf.ByteString bs = input.readBytes();\n                        bitField0_ |= 0x00000004;\n                        email_ = bs;\n                        break;\n                    }\n                    case 34: {\n                        if (!((mutable_bitField0_ & 0x00000008) == 0x00000008)) {\n                            cars_ = new java.util.ArrayList<com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.Car>();\n                            mutable_bitField0_ |= 0x00000008;\n                        }\n                        cars_.add(input.readMessage(\n                                com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.Car.PARSER, extensionRegistry));\n                        break;\n                    }\n                    }\n                }\n            } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n                throw e.setUnfinishedMessage(this);\n            } catch (java.io.IOException e) {\n                throw new com.google.protobuf.InvalidProtocolBufferException(e.getMessage()).setUnfinishedMessage(this);\n            } finally {\n                if (((mutable_bitField0_ & 0x00000008) == 0x00000008)) {\n                    cars_ = java.util.Collections.unmodifiableList(cars_);\n                }\n                this.unknownFields = unknownFields.build();\n                makeExtensionsImmutable();\n            }\n        }\n\n        public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() {\n            return com.lyncc.netty.codec.protobuf.demo.RichManProto.internal_static_netty_RichMan_descriptor;\n        }\n\n        protected com.google.protobuf.GeneratedMessage.FieldAccessorTable internalGetFieldAccessorTable() {\n            return com.lyncc.netty.codec.protobuf.demo.RichManProto.internal_static_netty_RichMan_fieldAccessorTable\n                    .ensureFieldAccessorsInitialized(com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.class,\n                            com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.Builder.class);\n        }\n\n        public static com.google.protobuf.Parser<RichMan> PARSER = new com.google.protobuf.AbstractParser<RichMan>() {\n            public RichMan parsePartialFrom(com.google.protobuf.CodedInputStream input,\n                    com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n                    throws com.google.protobuf.InvalidProtocolBufferException {\n                return new RichMan(input, extensionRegistry);\n            }\n        };\n\n        @java.lang.Override\n        public com.google.protobuf.Parser<RichMan> getParserForType() {\n            return PARSER;\n        }\n\n        /**\n         * Protobuf enum {@code netty.RichMan.CarType}\n         */\n        public enum CarType implements com.google.protobuf.ProtocolMessageEnum {\n            /**\n             * <code>AUDI = 0;</code>\n             */\n            AUDI(0, 0),\n            /**\n             * <code>BENZ = 1;</code>\n             */\n            BENZ(1, 1),\n            /**\n             * <code>LAMBORGHINI = 2;</code>\n             */\n            LAMBORGHINI(2, 2),\n            /**\n             * <code>DASAUTO = 3;</code>\n             */\n            DASAUTO(3, 3), ;\n\n            /**\n             * <code>AUDI = 0;</code>\n             */\n            public static final int AUDI_VALUE = 0;\n\n            /**\n             * <code>BENZ = 1;</code>\n             */\n            public static final int BENZ_VALUE = 1;\n\n            /**\n             * <code>LAMBORGHINI = 2;</code>\n             */\n            public static final int LAMBORGHINI_VALUE = 2;\n\n            /**\n             * <code>DASAUTO = 3;</code>\n             */\n            public static final int DASAUTO_VALUE = 3;\n\n            public final int getNumber() {\n                return value;\n            }\n\n            public static CarType valueOf(int value) {\n                switch (value) {\n                case 0:\n                    return AUDI;\n                case 1:\n                    return BENZ;\n                case 2:\n                    return LAMBORGHINI;\n                case 3:\n                    return DASAUTO;\n                default:\n                    return null;\n                }\n            }\n\n            public static com.google.protobuf.Internal.EnumLiteMap<CarType> internalGetValueMap() {\n                return internalValueMap;\n            }\n\n            private static com.google.protobuf.Internal.EnumLiteMap<CarType> internalValueMap = new com.google.protobuf.Internal.EnumLiteMap<CarType>() {\n                public CarType findValueByNumber(int number) {\n                    return CarType.valueOf(number);\n                }\n            };\n\n            public final com.google.protobuf.Descriptors.EnumValueDescriptor getValueDescriptor() {\n                return getDescriptor().getValues().get(index);\n            }\n\n            public final com.google.protobuf.Descriptors.EnumDescriptor getDescriptorForType() {\n                return getDescriptor();\n            }\n\n            public static final com.google.protobuf.Descriptors.EnumDescriptor getDescriptor() {\n                return com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.getDescriptor().getEnumTypes().get(0);\n            }\n\n            private static final CarType[] VALUES = values();\n\n            public static CarType valueOf(com.google.protobuf.Descriptors.EnumValueDescriptor desc) {\n                if (desc.getType() != getDescriptor()) {\n                    throw new java.lang.IllegalArgumentException(\"EnumValueDescriptor is not for this type.\");\n                }\n                return VALUES[desc.getIndex()];\n            }\n\n            private final int index;\n\n            private final int value;\n\n            private CarType(int index, int value) {\n                this.index = index;\n                this.value = value;\n            }\n\n            // @@protoc_insertion_point(enum_scope:netty.RichMan.CarType)\n        }\n\n        public interface CarOrBuilder extends\n        // @@protoc_insertion_point(interface_extends:netty.RichMan.Car)\n                com.google.protobuf.MessageOrBuilder {\n\n            /**\n             * <code>required string name = 1;</code>\n             */\n            boolean hasName();\n\n            /**\n             * <code>required string name = 1;</code>\n             */\n            java.lang.String getName();\n\n            /**\n             * <code>required string name = 1;</code>\n             */\n            com.google.protobuf.ByteString getNameBytes();\n\n            /**\n             * <code>optional .netty.RichMan.CarType type = 2 [default = BENZ];</code>\n             */\n            boolean hasType();\n\n            /**\n             * <code>optional .netty.RichMan.CarType type = 2 [default = BENZ];</code>\n             */\n            com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.CarType getType();\n        }\n\n        /**\n         * Protobuf type {@code netty.RichMan.Car}\n         */\n        public static final class Car extends com.google.protobuf.GeneratedMessage implements\n        // @@protoc_insertion_point(message_implements:netty.RichMan.Car)\n                CarOrBuilder {\n            // Use Car.newBuilder() to construct.\n            private Car(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n                super(builder);\n                this.unknownFields = builder.getUnknownFields();\n            }\n\n            private Car(boolean noInit) {\n                this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance();\n            }\n\n            private static final Car defaultInstance;\n\n            public static Car getDefaultInstance() {\n                return defaultInstance;\n            }\n\n            public Car getDefaultInstanceForType() {\n                return defaultInstance;\n            }\n\n            private final com.google.protobuf.UnknownFieldSet unknownFields;\n\n            @java.lang.Override\n            public final com.google.protobuf.UnknownFieldSet getUnknownFields() {\n                return this.unknownFields;\n            }\n\n            private Car(com.google.protobuf.CodedInputStream input,\n                    com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n                    throws com.google.protobuf.InvalidProtocolBufferException {\n                initFields();\n                int mutable_bitField0_ = 0;\n                com.google.protobuf.UnknownFieldSet.Builder unknownFields = com.google.protobuf.UnknownFieldSet\n                        .newBuilder();\n                try {\n                    boolean done = false;\n                    while (!done) {\n                        int tag = input.readTag();\n                        switch (tag) {\n                        case 0:\n                            done = true;\n                            break;\n                        default: {\n                            if (!parseUnknownField(input, unknownFields, extensionRegistry, tag)) {\n                                done = true;\n                            }\n                            break;\n                        }\n                        case 10: {\n                            com.google.protobuf.ByteString bs = input.readBytes();\n                            bitField0_ |= 0x00000001;\n                            name_ = bs;\n                            break;\n                        }\n                        case 16: {\n                            int rawValue = input.readEnum();\n                            com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.CarType value = com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.CarType\n                                    .valueOf(rawValue);\n                            if (value == null) {\n                                unknownFields.mergeVarintField(2, rawValue);\n                            } else {\n                                bitField0_ |= 0x00000002;\n                                type_ = value;\n                            }\n                            break;\n                        }\n                        }\n                    }\n                } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n                    throw e.setUnfinishedMessage(this);\n                } catch (java.io.IOException e) {\n                    throw new com.google.protobuf.InvalidProtocolBufferException(e.getMessage())\n                            .setUnfinishedMessage(this);\n                } finally {\n                    this.unknownFields = unknownFields.build();\n                    makeExtensionsImmutable();\n                }\n            }\n\n            public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() {\n                return com.lyncc.netty.codec.protobuf.demo.RichManProto.internal_static_netty_RichMan_Car_descriptor;\n            }\n\n            protected com.google.protobuf.GeneratedMessage.FieldAccessorTable internalGetFieldAccessorTable() {\n                return com.lyncc.netty.codec.protobuf.demo.RichManProto.internal_static_netty_RichMan_Car_fieldAccessorTable\n                        .ensureFieldAccessorsInitialized(\n                                com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.Car.class,\n                                com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.Car.Builder.class);\n            }\n\n            public static com.google.protobuf.Parser<Car> PARSER = new com.google.protobuf.AbstractParser<Car>() {\n                public Car parsePartialFrom(com.google.protobuf.CodedInputStream input,\n                        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n                        throws com.google.protobuf.InvalidProtocolBufferException {\n                    return new Car(input, extensionRegistry);\n                }\n            };\n\n            @java.lang.Override\n            public com.google.protobuf.Parser<Car> getParserForType() {\n                return PARSER;\n            }\n\n            private int bitField0_;\n\n            public static final int NAME_FIELD_NUMBER = 1;\n\n            private java.lang.Object name_;\n\n            /**\n             * <code>required string name = 1;</code>\n             */\n            public boolean hasName() {\n                return ((bitField0_ & 0x00000001) == 0x00000001);\n            }\n\n            /**\n             * <code>required string name = 1;</code>\n             */\n            public java.lang.String getName() {\n                java.lang.Object ref = name_;\n                if (ref instanceof java.lang.String) {\n                    return (java.lang.String) ref;\n                } else {\n                    com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref;\n                    java.lang.String s = bs.toStringUtf8();\n                    if (bs.isValidUtf8()) {\n                        name_ = s;\n                    }\n                    return s;\n                }\n            }\n\n            /**\n             * <code>required string name = 1;</code>\n             */\n            public com.google.protobuf.ByteString getNameBytes() {\n                java.lang.Object ref = name_;\n                if (ref instanceof java.lang.String) {\n                    com.google.protobuf.ByteString b = com.google.protobuf.ByteString\n                            .copyFromUtf8((java.lang.String) ref);\n                    name_ = b;\n                    return b;\n                } else {\n                    return (com.google.protobuf.ByteString) ref;\n                }\n            }\n\n            public static final int TYPE_FIELD_NUMBER = 2;\n\n            private com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.CarType type_;\n\n            /**\n             * <code>optional .netty.RichMan.CarType type = 2 [default = BENZ];</code>\n             */\n            public boolean hasType() {\n                return ((bitField0_ & 0x00000002) == 0x00000002);\n            }\n\n            /**\n             * <code>optional .netty.RichMan.CarType type = 2 [default = BENZ];</code>\n             */\n            public com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.CarType getType() {\n                return type_;\n            }\n\n            private void initFields() {\n                name_ = \"\";\n                type_ = com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.CarType.BENZ;\n            }\n\n            private byte memoizedIsInitialized = -1;\n\n            public final boolean isInitialized() {\n                byte isInitialized = memoizedIsInitialized;\n                if (isInitialized == 1)\n                    return true;\n                if (isInitialized == 0)\n                    return false;\n\n                if (!hasName()) {\n                    memoizedIsInitialized = 0;\n                    return false;\n                }\n                memoizedIsInitialized = 1;\n                return true;\n            }\n\n            public void writeTo(com.google.protobuf.CodedOutputStream output) throws java.io.IOException {\n                getSerializedSize();\n                if (((bitField0_ & 0x00000001) == 0x00000001)) {\n                    output.writeBytes(1, getNameBytes());\n                }\n                if (((bitField0_ & 0x00000002) == 0x00000002)) {\n                    output.writeEnum(2, type_.getNumber());\n                }\n                getUnknownFields().writeTo(output);\n            }\n\n            private int memoizedSerializedSize = -1;\n\n            public int getSerializedSize() {\n                int size = memoizedSerializedSize;\n                if (size != -1)\n                    return size;\n\n                size = 0;\n                if (((bitField0_ & 0x00000001) == 0x00000001)) {\n                    size += com.google.protobuf.CodedOutputStream.computeBytesSize(1, getNameBytes());\n                }\n                if (((bitField0_ & 0x00000002) == 0x00000002)) {\n                    size += com.google.protobuf.CodedOutputStream.computeEnumSize(2, type_.getNumber());\n                }\n                size += getUnknownFields().getSerializedSize();\n                memoizedSerializedSize = size;\n                return size;\n            }\n\n            private static final long serialVersionUID = 0L;\n\n            @java.lang.Override\n            protected java.lang.Object writeReplace() throws java.io.ObjectStreamException {\n                return super.writeReplace();\n            }\n\n            public static com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.Car parseFrom(\n                    com.google.protobuf.ByteString data) throws com.google.protobuf.InvalidProtocolBufferException {\n                return PARSER.parseFrom(data);\n            }\n\n            public static com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.Car parseFrom(\n                    com.google.protobuf.ByteString data, com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n                    throws com.google.protobuf.InvalidProtocolBufferException {\n                return PARSER.parseFrom(data, extensionRegistry);\n            }\n\n            public static com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.Car parseFrom(byte[] data)\n                    throws com.google.protobuf.InvalidProtocolBufferException {\n                return PARSER.parseFrom(data);\n            }\n\n            public static com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.Car parseFrom(byte[] data,\n                    com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n                    throws com.google.protobuf.InvalidProtocolBufferException {\n                return PARSER.parseFrom(data, extensionRegistry);\n            }\n\n            public static com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.Car parseFrom(\n                    java.io.InputStream input) throws java.io.IOException {\n                return PARSER.parseFrom(input);\n            }\n\n            public static com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.Car parseFrom(\n                    java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n                    throws java.io.IOException {\n                return PARSER.parseFrom(input, extensionRegistry);\n            }\n\n            public static com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.Car parseDelimitedFrom(\n                    java.io.InputStream input) throws java.io.IOException {\n                return PARSER.parseDelimitedFrom(input);\n            }\n\n            public static com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.Car parseDelimitedFrom(\n                    java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n                    throws java.io.IOException {\n                return PARSER.parseDelimitedFrom(input, extensionRegistry);\n            }\n\n            public static com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.Car parseFrom(\n                    com.google.protobuf.CodedInputStream input) throws java.io.IOException {\n                return PARSER.parseFrom(input);\n            }\n\n            public static com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.Car parseFrom(\n                    com.google.protobuf.CodedInputStream input,\n                    com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException {\n                return PARSER.parseFrom(input, extensionRegistry);\n            }\n\n            public static Builder newBuilder() {\n                return Builder.create();\n            }\n\n            public Builder newBuilderForType() {\n                return newBuilder();\n            }\n\n            public static Builder newBuilder(com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.Car prototype) {\n                return newBuilder().mergeFrom(prototype);\n            }\n\n            public Builder toBuilder() {\n                return newBuilder(this);\n            }\n\n            @java.lang.Override\n            protected Builder newBuilderForType(com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n                Builder builder = new Builder(parent);\n                return builder;\n            }\n\n            /**\n             * Protobuf type {@code netty.RichMan.Car}\n             */\n            public static final class Builder extends com.google.protobuf.GeneratedMessage.Builder<Builder> implements\n            // @@protoc_insertion_point(builder_implements:netty.RichMan.Car)\n                    com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.CarOrBuilder {\n                public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() {\n                    return com.lyncc.netty.codec.protobuf.demo.RichManProto.internal_static_netty_RichMan_Car_descriptor;\n                }\n\n                protected com.google.protobuf.GeneratedMessage.FieldAccessorTable internalGetFieldAccessorTable() {\n                    return com.lyncc.netty.codec.protobuf.demo.RichManProto.internal_static_netty_RichMan_Car_fieldAccessorTable\n                            .ensureFieldAccessorsInitialized(\n                                    com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.Car.class,\n                                    com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.Car.Builder.class);\n                }\n\n                // Construct using\n                // com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.Car.newBuilder()\n                private Builder() {\n                    maybeForceBuilderInitialization();\n                }\n\n                private Builder(com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n                    super(parent);\n                    maybeForceBuilderInitialization();\n                }\n\n                private void maybeForceBuilderInitialization() {\n                    if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n                    }\n                }\n\n                private static Builder create() {\n                    return new Builder();\n                }\n\n                public Builder clear() {\n                    super.clear();\n                    name_ = \"\";\n                    bitField0_ = (bitField0_ & ~0x00000001);\n                    type_ = com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.CarType.BENZ;\n                    bitField0_ = (bitField0_ & ~0x00000002);\n                    return this;\n                }\n\n                public Builder clone() {\n                    return create().mergeFrom(buildPartial());\n                }\n\n                public com.google.protobuf.Descriptors.Descriptor getDescriptorForType() {\n                    return com.lyncc.netty.codec.protobuf.demo.RichManProto.internal_static_netty_RichMan_Car_descriptor;\n                }\n\n                public com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.Car getDefaultInstanceForType() {\n                    return com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.Car.getDefaultInstance();\n                }\n\n                public com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.Car build() {\n                    com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.Car result = buildPartial();\n                    if (!result.isInitialized()) {\n                        throw newUninitializedMessageException(result);\n                    }\n                    return result;\n                }\n\n                public com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.Car buildPartial() {\n                    com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.Car result = new com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.Car(\n                            this);\n                    int from_bitField0_ = bitField0_;\n                    int to_bitField0_ = 0;\n                    if (((from_bitField0_ & 0x00000001) == 0x00000001)) {\n                        to_bitField0_ |= 0x00000001;\n                    }\n                    result.name_ = name_;\n                    if (((from_bitField0_ & 0x00000002) == 0x00000002)) {\n                        to_bitField0_ |= 0x00000002;\n                    }\n                    result.type_ = type_;\n                    result.bitField0_ = to_bitField0_;\n                    onBuilt();\n                    return result;\n                }\n\n                public Builder mergeFrom(com.google.protobuf.Message other) {\n                    if (other instanceof com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.Car) {\n                        return mergeFrom((com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.Car) other);\n                    } else {\n                        super.mergeFrom(other);\n                        return this;\n                    }\n                }\n\n                public Builder mergeFrom(com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.Car other) {\n                    if (other == com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.Car.getDefaultInstance())\n                        return this;\n                    if (other.hasName()) {\n                        bitField0_ |= 0x00000001;\n                        name_ = other.name_;\n                        onChanged();\n                    }\n                    if (other.hasType()) {\n                        setType(other.getType());\n                    }\n                    this.mergeUnknownFields(other.getUnknownFields());\n                    return this;\n                }\n\n                public final boolean isInitialized() {\n                    if (!hasName()) {\n\n                        return false;\n                    }\n                    return true;\n                }\n\n                public Builder mergeFrom(com.google.protobuf.CodedInputStream input,\n                        com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException {\n                    com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.Car parsedMessage = null;\n                    try {\n                        parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n                    } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n                        parsedMessage = (com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.Car) e\n                                .getUnfinishedMessage();\n                        throw e;\n                    } finally {\n                        if (parsedMessage != null) {\n                            mergeFrom(parsedMessage);\n                        }\n                    }\n                    return this;\n                }\n\n                private int bitField0_;\n\n                private java.lang.Object name_ = \"\";\n\n                /**\n                 * <code>required string name = 1;</code>\n                 */\n                public boolean hasName() {\n                    return ((bitField0_ & 0x00000001) == 0x00000001);\n                }\n\n                /**\n                 * <code>required string name = 1;</code>\n                 */\n                public java.lang.String getName() {\n                    java.lang.Object ref = name_;\n                    if (!(ref instanceof java.lang.String)) {\n                        com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref;\n                        java.lang.String s = bs.toStringUtf8();\n                        if (bs.isValidUtf8()) {\n                            name_ = s;\n                        }\n                        return s;\n                    } else {\n                        return (java.lang.String) ref;\n                    }\n                }\n\n                /**\n                 * <code>required string name = 1;</code>\n                 */\n                public com.google.protobuf.ByteString getNameBytes() {\n                    java.lang.Object ref = name_;\n                    if (ref instanceof String) {\n                        com.google.protobuf.ByteString b = com.google.protobuf.ByteString\n                                .copyFromUtf8((java.lang.String) ref);\n                        name_ = b;\n                        return b;\n                    } else {\n                        return (com.google.protobuf.ByteString) ref;\n                    }\n                }\n\n                /**\n                 * <code>required string name = 1;</code>\n                 */\n                public Builder setName(java.lang.String value) {\n                    if (value == null) {\n                        throw new NullPointerException();\n                    }\n                    bitField0_ |= 0x00000001;\n                    name_ = value;\n                    onChanged();\n                    return this;\n                }\n\n                /**\n                 * <code>required string name = 1;</code>\n                 */\n                public Builder clearName() {\n                    bitField0_ = (bitField0_ & ~0x00000001);\n                    name_ = getDefaultInstance().getName();\n                    onChanged();\n                    return this;\n                }\n\n                /**\n                 * <code>required string name = 1;</code>\n                 */\n                public Builder setNameBytes(com.google.protobuf.ByteString value) {\n                    if (value == null) {\n                        throw new NullPointerException();\n                    }\n                    bitField0_ |= 0x00000001;\n                    name_ = value;\n                    onChanged();\n                    return this;\n                }\n\n                private com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.CarType type_ = com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.CarType.BENZ;\n\n                /**\n                 * <code>optional .netty.RichMan.CarType type = 2 [default = BENZ];</code>\n                 */\n                public boolean hasType() {\n                    return ((bitField0_ & 0x00000002) == 0x00000002);\n                }\n\n                /**\n                 * <code>optional .netty.RichMan.CarType type = 2 [default = BENZ];</code>\n                 */\n                public com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.CarType getType() {\n                    return type_;\n                }\n\n                /**\n                 * <code>optional .netty.RichMan.CarType type = 2 [default = BENZ];</code>\n                 */\n                public Builder setType(com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.CarType value) {\n                    if (value == null) {\n                        throw new NullPointerException();\n                    }\n                    bitField0_ |= 0x00000002;\n                    type_ = value;\n                    onChanged();\n                    return this;\n                }\n\n                /**\n                 * <code>optional .netty.RichMan.CarType type = 2 [default = BENZ];</code>\n                 */\n                public Builder clearType() {\n                    bitField0_ = (bitField0_ & ~0x00000002);\n                    type_ = com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.CarType.BENZ;\n                    onChanged();\n                    return this;\n                }\n\n                // @@protoc_insertion_point(builder_scope:netty.RichMan.Car)\n            }\n\n            static {\n                defaultInstance = new Car(true);\n                defaultInstance.initFields();\n            }\n\n            // @@protoc_insertion_point(class_scope:netty.RichMan.Car)\n        }\n\n        private int bitField0_;\n\n        public static final int ID_FIELD_NUMBER = 1;\n\n        private int id_;\n\n        /**\n         * <code>required int32 id = 1;</code>\n         */\n        public boolean hasId() {\n            return ((bitField0_ & 0x00000001) == 0x00000001);\n        }\n\n        /**\n         * <code>required int32 id = 1;</code>\n         */\n        public int getId() {\n            return id_;\n        }\n\n        public static final int NAME_FIELD_NUMBER = 2;\n\n        private java.lang.Object name_;\n\n        /**\n         * <code>required string name = 2;</code>\n         */\n        public boolean hasName() {\n            return ((bitField0_ & 0x00000002) == 0x00000002);\n        }\n\n        /**\n         * <code>required string name = 2;</code>\n         */\n        public java.lang.String getName() {\n            java.lang.Object ref = name_;\n            if (ref instanceof java.lang.String) {\n                return (java.lang.String) ref;\n            } else {\n                com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref;\n                java.lang.String s = bs.toStringUtf8();\n                if (bs.isValidUtf8()) {\n                    name_ = s;\n                }\n                return s;\n            }\n        }\n\n        /**\n         * <code>required string name = 2;</code>\n         */\n        public com.google.protobuf.ByteString getNameBytes() {\n            java.lang.Object ref = name_;\n            if (ref instanceof java.lang.String) {\n                com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8((java.lang.String) ref);\n                name_ = b;\n                return b;\n            } else {\n                return (com.google.protobuf.ByteString) ref;\n            }\n        }\n\n        public static final int EMAIL_FIELD_NUMBER = 3;\n\n        private java.lang.Object email_;\n\n        /**\n         * <code>optional string email = 3;</code>\n         */\n        public boolean hasEmail() {\n            return ((bitField0_ & 0x00000004) == 0x00000004);\n        }\n\n        /**\n         * <code>optional string email = 3;</code>\n         */\n        public java.lang.String getEmail() {\n            java.lang.Object ref = email_;\n            if (ref instanceof java.lang.String) {\n                return (java.lang.String) ref;\n            } else {\n                com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref;\n                java.lang.String s = bs.toStringUtf8();\n                if (bs.isValidUtf8()) {\n                    email_ = s;\n                }\n                return s;\n            }\n        }\n\n        /**\n         * <code>optional string email = 3;</code>\n         */\n        public com.google.protobuf.ByteString getEmailBytes() {\n            java.lang.Object ref = email_;\n            if (ref instanceof java.lang.String) {\n                com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8((java.lang.String) ref);\n                email_ = b;\n                return b;\n            } else {\n                return (com.google.protobuf.ByteString) ref;\n            }\n        }\n\n        public static final int CARS_FIELD_NUMBER = 4;\n\n        private java.util.List<com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.Car> cars_;\n\n        /**\n         * <code>repeated .netty.RichMan.Car cars = 4;</code>\n         */\n        public java.util.List<com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.Car> getCarsList() {\n            return cars_;\n        }\n\n        /**\n         * <code>repeated .netty.RichMan.Car cars = 4;</code>\n         */\n        public java.util.List<? extends com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.CarOrBuilder> getCarsOrBuilderList() {\n            return cars_;\n        }\n\n        /**\n         * <code>repeated .netty.RichMan.Car cars = 4;</code>\n         */\n        public int getCarsCount() {\n            return cars_.size();\n        }\n\n        /**\n         * <code>repeated .netty.RichMan.Car cars = 4;</code>\n         */\n        public com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.Car getCars(int index) {\n            return cars_.get(index);\n        }\n\n        /**\n         * <code>repeated .netty.RichMan.Car cars = 4;</code>\n         */\n        public com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.CarOrBuilder getCarsOrBuilder(int index) {\n            return cars_.get(index);\n        }\n\n        private void initFields() {\n            id_ = 0;\n            name_ = \"\";\n            email_ = \"\";\n            cars_ = java.util.Collections.emptyList();\n        }\n\n        private byte memoizedIsInitialized = -1;\n\n        public final boolean isInitialized() {\n            byte isInitialized = memoizedIsInitialized;\n            if (isInitialized == 1)\n                return true;\n            if (isInitialized == 0)\n                return false;\n\n            if (!hasId()) {\n                memoizedIsInitialized = 0;\n                return false;\n            }\n            if (!hasName()) {\n                memoizedIsInitialized = 0;\n                return false;\n            }\n            for (int i = 0; i < getCarsCount(); i++) {\n                if (!getCars(i).isInitialized()) {\n                    memoizedIsInitialized = 0;\n                    return false;\n                }\n            }\n            memoizedIsInitialized = 1;\n            return true;\n        }\n\n        public void writeTo(com.google.protobuf.CodedOutputStream output) throws java.io.IOException {\n            getSerializedSize();\n            if (((bitField0_ & 0x00000001) == 0x00000001)) {\n                output.writeInt32(1, id_);\n            }\n            if (((bitField0_ & 0x00000002) == 0x00000002)) {\n                output.writeBytes(2, getNameBytes());\n            }\n            if (((bitField0_ & 0x00000004) == 0x00000004)) {\n                output.writeBytes(3, getEmailBytes());\n            }\n            for (int i = 0; i < cars_.size(); i++) {\n                output.writeMessage(4, cars_.get(i));\n            }\n            getUnknownFields().writeTo(output);\n        }\n\n        private int memoizedSerializedSize = -1;\n\n        public int getSerializedSize() {\n            int size = memoizedSerializedSize;\n            if (size != -1)\n                return size;\n\n            size = 0;\n            if (((bitField0_ & 0x00000001) == 0x00000001)) {\n                size += com.google.protobuf.CodedOutputStream.computeInt32Size(1, id_);\n            }\n            if (((bitField0_ & 0x00000002) == 0x00000002)) {\n                size += com.google.protobuf.CodedOutputStream.computeBytesSize(2, getNameBytes());\n            }\n            if (((bitField0_ & 0x00000004) == 0x00000004)) {\n                size += com.google.protobuf.CodedOutputStream.computeBytesSize(3, getEmailBytes());\n            }\n            for (int i = 0; i < cars_.size(); i++) {\n                size += com.google.protobuf.CodedOutputStream.computeMessageSize(4, cars_.get(i));\n            }\n            size += getUnknownFields().getSerializedSize();\n            memoizedSerializedSize = size;\n            return size;\n        }\n\n        private static final long serialVersionUID = 0L;\n\n        @java.lang.Override\n        protected java.lang.Object writeReplace() throws java.io.ObjectStreamException {\n            return super.writeReplace();\n        }\n\n        public static com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan parseFrom(\n                com.google.protobuf.ByteString data) throws com.google.protobuf.InvalidProtocolBufferException {\n            return PARSER.parseFrom(data);\n        }\n\n        public static com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan parseFrom(\n                com.google.protobuf.ByteString data, com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n                throws com.google.protobuf.InvalidProtocolBufferException {\n            return PARSER.parseFrom(data, extensionRegistry);\n        }\n\n        public static com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan parseFrom(byte[] data)\n                throws com.google.protobuf.InvalidProtocolBufferException {\n            return PARSER.parseFrom(data);\n        }\n\n        public static com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan parseFrom(byte[] data,\n                com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n                throws com.google.protobuf.InvalidProtocolBufferException {\n            return PARSER.parseFrom(data, extensionRegistry);\n        }\n\n        public static com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan parseFrom(java.io.InputStream input)\n                throws java.io.IOException {\n            return PARSER.parseFrom(input);\n        }\n\n        public static com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan parseFrom(java.io.InputStream input,\n                com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException {\n            return PARSER.parseFrom(input, extensionRegistry);\n        }\n\n        public static com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan parseDelimitedFrom(\n                java.io.InputStream input) throws java.io.IOException {\n            return PARSER.parseDelimitedFrom(input);\n        }\n\n        public static com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan parseDelimitedFrom(\n                java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n                throws java.io.IOException {\n            return PARSER.parseDelimitedFrom(input, extensionRegistry);\n        }\n\n        public static com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan parseFrom(\n                com.google.protobuf.CodedInputStream input) throws java.io.IOException {\n            return PARSER.parseFrom(input);\n        }\n\n        public static com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan parseFrom(\n                com.google.protobuf.CodedInputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n                throws java.io.IOException {\n            return PARSER.parseFrom(input, extensionRegistry);\n        }\n\n        public static Builder newBuilder() {\n            return Builder.create();\n        }\n\n        public Builder newBuilderForType() {\n            return newBuilder();\n        }\n\n        public static Builder newBuilder(com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan prototype) {\n            return newBuilder().mergeFrom(prototype);\n        }\n\n        public Builder toBuilder() {\n            return newBuilder(this);\n        }\n\n        @java.lang.Override\n        protected Builder newBuilderForType(com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n            Builder builder = new Builder(parent);\n            return builder;\n        }\n\n        /**\n         * Protobuf type {@code netty.RichMan}\n         */\n        public static final class Builder extends com.google.protobuf.GeneratedMessage.Builder<Builder> implements\n        // @@protoc_insertion_point(builder_implements:netty.RichMan)\n                com.lyncc.netty.codec.protobuf.demo.RichManProto.RichManOrBuilder {\n            public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() {\n                return com.lyncc.netty.codec.protobuf.demo.RichManProto.internal_static_netty_RichMan_descriptor;\n            }\n\n            protected com.google.protobuf.GeneratedMessage.FieldAccessorTable internalGetFieldAccessorTable() {\n                return com.lyncc.netty.codec.protobuf.demo.RichManProto.internal_static_netty_RichMan_fieldAccessorTable\n                        .ensureFieldAccessorsInitialized(\n                                com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.class,\n                                com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.Builder.class);\n            }\n\n            // Construct using\n            // com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.newBuilder()\n            private Builder() {\n                maybeForceBuilderInitialization();\n            }\n\n            private Builder(com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n                super(parent);\n                maybeForceBuilderInitialization();\n            }\n\n            private void maybeForceBuilderInitialization() {\n                if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n                    getCarsFieldBuilder();\n                }\n            }\n\n            private static Builder create() {\n                return new Builder();\n            }\n\n            public Builder clear() {\n                super.clear();\n                id_ = 0;\n                bitField0_ = (bitField0_ & ~0x00000001);\n                name_ = \"\";\n                bitField0_ = (bitField0_ & ~0x00000002);\n                email_ = \"\";\n                bitField0_ = (bitField0_ & ~0x00000004);\n                if (carsBuilder_ == null) {\n                    cars_ = java.util.Collections.emptyList();\n                    bitField0_ = (bitField0_ & ~0x00000008);\n                } else {\n                    carsBuilder_.clear();\n                }\n                return this;\n            }\n\n            public Builder clone() {\n                return create().mergeFrom(buildPartial());\n            }\n\n            public com.google.protobuf.Descriptors.Descriptor getDescriptorForType() {\n                return com.lyncc.netty.codec.protobuf.demo.RichManProto.internal_static_netty_RichMan_descriptor;\n            }\n\n            public com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan getDefaultInstanceForType() {\n                return com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.getDefaultInstance();\n            }\n\n            public com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan build() {\n                com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan result = buildPartial();\n                if (!result.isInitialized()) {\n                    throw newUninitializedMessageException(result);\n                }\n                return result;\n            }\n\n            public com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan buildPartial() {\n                com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan result = new com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan(\n                        this);\n                int from_bitField0_ = bitField0_;\n                int to_bitField0_ = 0;\n                if (((from_bitField0_ & 0x00000001) == 0x00000001)) {\n                    to_bitField0_ |= 0x00000001;\n                }\n                result.id_ = id_;\n                if (((from_bitField0_ & 0x00000002) == 0x00000002)) {\n                    to_bitField0_ |= 0x00000002;\n                }\n                result.name_ = name_;\n                if (((from_bitField0_ & 0x00000004) == 0x00000004)) {\n                    to_bitField0_ |= 0x00000004;\n                }\n                result.email_ = email_;\n                if (carsBuilder_ == null) {\n                    if (((bitField0_ & 0x00000008) == 0x00000008)) {\n                        cars_ = java.util.Collections.unmodifiableList(cars_);\n                        bitField0_ = (bitField0_ & ~0x00000008);\n                    }\n                    result.cars_ = cars_;\n                } else {\n                    result.cars_ = carsBuilder_.build();\n                }\n                result.bitField0_ = to_bitField0_;\n                onBuilt();\n                return result;\n            }\n\n            public Builder mergeFrom(com.google.protobuf.Message other) {\n                if (other instanceof com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan) {\n                    return mergeFrom((com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan) other);\n                } else {\n                    super.mergeFrom(other);\n                    return this;\n                }\n            }\n\n            public Builder mergeFrom(com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan other) {\n                if (other == com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.getDefaultInstance())\n                    return this;\n                if (other.hasId()) {\n                    setId(other.getId());\n                }\n                if (other.hasName()) {\n                    bitField0_ |= 0x00000002;\n                    name_ = other.name_;\n                    onChanged();\n                }\n                if (other.hasEmail()) {\n                    bitField0_ |= 0x00000004;\n                    email_ = other.email_;\n                    onChanged();\n                }\n                if (carsBuilder_ == null) {\n                    if (!other.cars_.isEmpty()) {\n                        if (cars_.isEmpty()) {\n                            cars_ = other.cars_;\n                            bitField0_ = (bitField0_ & ~0x00000008);\n                        } else {\n                            ensureCarsIsMutable();\n                            cars_.addAll(other.cars_);\n                        }\n                        onChanged();\n                    }\n                } else {\n                    if (!other.cars_.isEmpty()) {\n                        if (carsBuilder_.isEmpty()) {\n                            carsBuilder_.dispose();\n                            carsBuilder_ = null;\n                            cars_ = other.cars_;\n                            bitField0_ = (bitField0_ & ~0x00000008);\n                            carsBuilder_ = com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ? getCarsFieldBuilder()\n                                    : null;\n                        } else {\n                            carsBuilder_.addAllMessages(other.cars_);\n                        }\n                    }\n                }\n                this.mergeUnknownFields(other.getUnknownFields());\n                return this;\n            }\n\n            public final boolean isInitialized() {\n                if (!hasId()) {\n\n                    return false;\n                }\n                if (!hasName()) {\n\n                    return false;\n                }\n                for (int i = 0; i < getCarsCount(); i++) {\n                    if (!getCars(i).isInitialized()) {\n\n                        return false;\n                    }\n                }\n                return true;\n            }\n\n            public Builder mergeFrom(com.google.protobuf.CodedInputStream input,\n                    com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException {\n                com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan parsedMessage = null;\n                try {\n                    parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n                } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n                    parsedMessage = (com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan) e.getUnfinishedMessage();\n                    throw e;\n                } finally {\n                    if (parsedMessage != null) {\n                        mergeFrom(parsedMessage);\n                    }\n                }\n                return this;\n            }\n\n            private int bitField0_;\n\n            private int id_;\n\n            /**\n             * <code>required int32 id = 1;</code>\n             */\n            public boolean hasId() {\n                return ((bitField0_ & 0x00000001) == 0x00000001);\n            }\n\n            /**\n             * <code>required int32 id = 1;</code>\n             */\n            public int getId() {\n                return id_;\n            }\n\n            /**\n             * <code>required int32 id = 1;</code>\n             */\n            public Builder setId(int value) {\n                bitField0_ |= 0x00000001;\n                id_ = value;\n                onChanged();\n                return this;\n            }\n\n            /**\n             * <code>required int32 id = 1;</code>\n             */\n            public Builder clearId() {\n                bitField0_ = (bitField0_ & ~0x00000001);\n                id_ = 0;\n                onChanged();\n                return this;\n            }\n\n            private java.lang.Object name_ = \"\";\n\n            /**\n             * <code>required string name = 2;</code>\n             */\n            public boolean hasName() {\n                return ((bitField0_ & 0x00000002) == 0x00000002);\n            }\n\n            /**\n             * <code>required string name = 2;</code>\n             */\n            public java.lang.String getName() {\n                java.lang.Object ref = name_;\n                if (!(ref instanceof java.lang.String)) {\n                    com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref;\n                    java.lang.String s = bs.toStringUtf8();\n                    if (bs.isValidUtf8()) {\n                        name_ = s;\n                    }\n                    return s;\n                } else {\n                    return (java.lang.String) ref;\n                }\n            }\n\n            /**\n             * <code>required string name = 2;</code>\n             */\n            public com.google.protobuf.ByteString getNameBytes() {\n                java.lang.Object ref = name_;\n                if (ref instanceof String) {\n                    com.google.protobuf.ByteString b = com.google.protobuf.ByteString\n                            .copyFromUtf8((java.lang.String) ref);\n                    name_ = b;\n                    return b;\n                } else {\n                    return (com.google.protobuf.ByteString) ref;\n                }\n            }\n\n            /**\n             * <code>required string name = 2;</code>\n             */\n            public Builder setName(java.lang.String value) {\n                if (value == null) {\n                    throw new NullPointerException();\n                }\n                bitField0_ |= 0x00000002;\n                name_ = value;\n                onChanged();\n                return this;\n            }\n\n            /**\n             * <code>required string name = 2;</code>\n             */\n            public Builder clearName() {\n                bitField0_ = (bitField0_ & ~0x00000002);\n                name_ = getDefaultInstance().getName();\n                onChanged();\n                return this;\n            }\n\n            /**\n             * <code>required string name = 2;</code>\n             */\n            public Builder setNameBytes(com.google.protobuf.ByteString value) {\n                if (value == null) {\n                    throw new NullPointerException();\n                }\n                bitField0_ |= 0x00000002;\n                name_ = value;\n                onChanged();\n                return this;\n            }\n\n            private java.lang.Object email_ = \"\";\n\n            /**\n             * <code>optional string email = 3;</code>\n             */\n            public boolean hasEmail() {\n                return ((bitField0_ & 0x00000004) == 0x00000004);\n            }\n\n            /**\n             * <code>optional string email = 3;</code>\n             */\n            public java.lang.String getEmail() {\n                java.lang.Object ref = email_;\n                if (!(ref instanceof java.lang.String)) {\n                    com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref;\n                    java.lang.String s = bs.toStringUtf8();\n                    if (bs.isValidUtf8()) {\n                        email_ = s;\n                    }\n                    return s;\n                } else {\n                    return (java.lang.String) ref;\n                }\n            }\n\n            /**\n             * <code>optional string email = 3;</code>\n             */\n            public com.google.protobuf.ByteString getEmailBytes() {\n                java.lang.Object ref = email_;\n                if (ref instanceof String) {\n                    com.google.protobuf.ByteString b = com.google.protobuf.ByteString\n                            .copyFromUtf8((java.lang.String) ref);\n                    email_ = b;\n                    return b;\n                } else {\n                    return (com.google.protobuf.ByteString) ref;\n                }\n            }\n\n            /**\n             * <code>optional string email = 3;</code>\n             */\n            public Builder setEmail(java.lang.String value) {\n                if (value == null) {\n                    throw new NullPointerException();\n                }\n                bitField0_ |= 0x00000004;\n                email_ = value;\n                onChanged();\n                return this;\n            }\n\n            /**\n             * <code>optional string email = 3;</code>\n             */\n            public Builder clearEmail() {\n                bitField0_ = (bitField0_ & ~0x00000004);\n                email_ = getDefaultInstance().getEmail();\n                onChanged();\n                return this;\n            }\n\n            /**\n             * <code>optional string email = 3;</code>\n             */\n            public Builder setEmailBytes(com.google.protobuf.ByteString value) {\n                if (value == null) {\n                    throw new NullPointerException();\n                }\n                bitField0_ |= 0x00000004;\n                email_ = value;\n                onChanged();\n                return this;\n            }\n\n            private java.util.List<com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.Car> cars_ = java.util.Collections\n                    .emptyList();\n\n            private void ensureCarsIsMutable() {\n                if (!((bitField0_ & 0x00000008) == 0x00000008)) {\n                    cars_ = new java.util.ArrayList<com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.Car>(cars_);\n                    bitField0_ |= 0x00000008;\n                }\n            }\n\n            private com.google.protobuf.RepeatedFieldBuilder<com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.Car, com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.Car.Builder, com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.CarOrBuilder> carsBuilder_;\n\n            /**\n             * <code>repeated .netty.RichMan.Car cars = 4;</code>\n             */\n            public java.util.List<com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.Car> getCarsList() {\n                if (carsBuilder_ == null) {\n                    return java.util.Collections.unmodifiableList(cars_);\n                } else {\n                    return carsBuilder_.getMessageList();\n                }\n            }\n\n            /**\n             * <code>repeated .netty.RichMan.Car cars = 4;</code>\n             */\n            public int getCarsCount() {\n                if (carsBuilder_ == null) {\n                    return cars_.size();\n                } else {\n                    return carsBuilder_.getCount();\n                }\n            }\n\n            /**\n             * <code>repeated .netty.RichMan.Car cars = 4;</code>\n             */\n            public com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.Car getCars(int index) {\n                if (carsBuilder_ == null) {\n                    return cars_.get(index);\n                } else {\n                    return carsBuilder_.getMessage(index);\n                }\n            }\n\n            /**\n             * <code>repeated .netty.RichMan.Car cars = 4;</code>\n             */\n            public Builder setCars(int index, com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.Car value) {\n                if (carsBuilder_ == null) {\n                    if (value == null) {\n                        throw new NullPointerException();\n                    }\n                    ensureCarsIsMutable();\n                    cars_.set(index, value);\n                    onChanged();\n                } else {\n                    carsBuilder_.setMessage(index, value);\n                }\n                return this;\n            }\n\n            /**\n             * <code>repeated .netty.RichMan.Car cars = 4;</code>\n             */\n            public Builder setCars(int index,\n                    com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.Car.Builder builderForValue) {\n                if (carsBuilder_ == null) {\n                    ensureCarsIsMutable();\n                    cars_.set(index, builderForValue.build());\n                    onChanged();\n                } else {\n                    carsBuilder_.setMessage(index, builderForValue.build());\n                }\n                return this;\n            }\n\n            /**\n             * <code>repeated .netty.RichMan.Car cars = 4;</code>\n             */\n            public Builder addCars(com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.Car value) {\n                if (carsBuilder_ == null) {\n                    if (value == null) {\n                        throw new NullPointerException();\n                    }\n                    ensureCarsIsMutable();\n                    cars_.add(value);\n                    onChanged();\n                } else {\n                    carsBuilder_.addMessage(value);\n                }\n                return this;\n            }\n\n            /**\n             * <code>repeated .netty.RichMan.Car cars = 4;</code>\n             */\n            public Builder addCars(int index, com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.Car value) {\n                if (carsBuilder_ == null) {\n                    if (value == null) {\n                        throw new NullPointerException();\n                    }\n                    ensureCarsIsMutable();\n                    cars_.add(index, value);\n                    onChanged();\n                } else {\n                    carsBuilder_.addMessage(index, value);\n                }\n                return this;\n            }\n\n            /**\n             * <code>repeated .netty.RichMan.Car cars = 4;</code>\n             */\n            public Builder addCars(com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.Car.Builder builderForValue) {\n                if (carsBuilder_ == null) {\n                    ensureCarsIsMutable();\n                    cars_.add(builderForValue.build());\n                    onChanged();\n                } else {\n                    carsBuilder_.addMessage(builderForValue.build());\n                }\n                return this;\n            }\n\n            /**\n             * <code>repeated .netty.RichMan.Car cars = 4;</code>\n             */\n            public Builder addCars(int index,\n                    com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.Car.Builder builderForValue) {\n                if (carsBuilder_ == null) {\n                    ensureCarsIsMutable();\n                    cars_.add(index, builderForValue.build());\n                    onChanged();\n                } else {\n                    carsBuilder_.addMessage(index, builderForValue.build());\n                }\n                return this;\n            }\n\n            /**\n             * <code>repeated .netty.RichMan.Car cars = 4;</code>\n             */\n            public Builder addAllCars(\n                    java.lang.Iterable<? extends com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.Car> values) {\n                if (carsBuilder_ == null) {\n                    ensureCarsIsMutable();\n                    com.google.protobuf.AbstractMessageLite.Builder.addAll(values, cars_);\n                    onChanged();\n                } else {\n                    carsBuilder_.addAllMessages(values);\n                }\n                return this;\n            }\n\n            /**\n             * <code>repeated .netty.RichMan.Car cars = 4;</code>\n             */\n            public Builder clearCars() {\n                if (carsBuilder_ == null) {\n                    cars_ = java.util.Collections.emptyList();\n                    bitField0_ = (bitField0_ & ~0x00000008);\n                    onChanged();\n                } else {\n                    carsBuilder_.clear();\n                }\n                return this;\n            }\n\n            /**\n             * <code>repeated .netty.RichMan.Car cars = 4;</code>\n             */\n            public Builder removeCars(int index) {\n                if (carsBuilder_ == null) {\n                    ensureCarsIsMutable();\n                    cars_.remove(index);\n                    onChanged();\n                } else {\n                    carsBuilder_.remove(index);\n                }\n                return this;\n            }\n\n            /**\n             * <code>repeated .netty.RichMan.Car cars = 4;</code>\n             */\n            public com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.Car.Builder getCarsBuilder(int index) {\n                return getCarsFieldBuilder().getBuilder(index);\n            }\n\n            /**\n             * <code>repeated .netty.RichMan.Car cars = 4;</code>\n             */\n            public com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.CarOrBuilder getCarsOrBuilder(int index) {\n                if (carsBuilder_ == null) {\n                    return cars_.get(index);\n                } else {\n                    return carsBuilder_.getMessageOrBuilder(index);\n                }\n            }\n\n            /**\n             * <code>repeated .netty.RichMan.Car cars = 4;</code>\n             */\n            public java.util.List<? extends com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.CarOrBuilder> getCarsOrBuilderList() {\n                if (carsBuilder_ != null) {\n                    return carsBuilder_.getMessageOrBuilderList();\n                } else {\n                    return java.util.Collections.unmodifiableList(cars_);\n                }\n            }\n\n            /**\n             * <code>repeated .netty.RichMan.Car cars = 4;</code>\n             */\n            public com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.Car.Builder addCarsBuilder() {\n                return getCarsFieldBuilder().addBuilder(\n                        com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.Car.getDefaultInstance());\n            }\n\n            /**\n             * <code>repeated .netty.RichMan.Car cars = 4;</code>\n             */\n            public com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.Car.Builder addCarsBuilder(int index) {\n                return getCarsFieldBuilder().addBuilder(index,\n                        com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.Car.getDefaultInstance());\n            }\n\n            /**\n             * <code>repeated .netty.RichMan.Car cars = 4;</code>\n             */\n            public java.util.List<com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.Car.Builder> getCarsBuilderList() {\n                return getCarsFieldBuilder().getBuilderList();\n            }\n\n            private com.google.protobuf.RepeatedFieldBuilder<com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.Car, com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.Car.Builder, com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.CarOrBuilder> getCarsFieldBuilder() {\n                if (carsBuilder_ == null) {\n                    carsBuilder_ = new com.google.protobuf.RepeatedFieldBuilder<com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.Car, com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.Car.Builder, com.lyncc.netty.codec.protobuf.demo.RichManProto.RichMan.CarOrBuilder>(\n                            cars_, ((bitField0_ & 0x00000008) == 0x00000008), getParentForChildren(), isClean());\n                    cars_ = null;\n                }\n                return carsBuilder_;\n            }\n\n            // @@protoc_insertion_point(builder_scope:netty.RichMan)\n        }\n\n        static {\n            defaultInstance = new RichMan(true);\n            defaultInstance.initFields();\n        }\n\n        // @@protoc_insertion_point(class_scope:netty.RichMan)\n    }\n\n    private static final com.google.protobuf.Descriptors.Descriptor internal_static_netty_RichMan_descriptor;\n\n    private static com.google.protobuf.GeneratedMessage.FieldAccessorTable internal_static_netty_RichMan_fieldAccessorTable;\n\n    private static final com.google.protobuf.Descriptors.Descriptor internal_static_netty_RichMan_Car_descriptor;\n\n    private static com.google.protobuf.GeneratedMessage.FieldAccessorTable internal_static_netty_RichMan_Car_fieldAccessorTable;\n\n    public static com.google.protobuf.Descriptors.FileDescriptor getDescriptor() {\n        return descriptor;\n    }\n\n    private static com.google.protobuf.Descriptors.FileDescriptor descriptor;\n    static {\n        java.lang.String[] descriptorData = { \"\\n\\rRichMan.proto\\022\\005netty\\\"\\322\\001\\n\\007RichMan\\022\\n\\n\\002id\"\n                + \"\\030\\001 \\002(\\005\\022\\014\\n\\004name\\030\\002 \\002(\\t\\022\\r\\n\\005email\\030\\003 \\001(\\t\\022 \\n\\004c\"\n                + \"ars\\030\\004 \\003(\\0132\\022.netty.RichMan.Car\\032?\\n\\003Car\\022\\014\\n\\004\"\n                + \"name\\030\\001 \\002(\\t\\022*\\n\\004type\\030\\002 \\001(\\0162\\026.netty.RichMan\"\n                + \".CarType:\\004BENZ\\\";\\n\\007CarType\\022\\010\\n\\004AUDI\\020\\000\\022\\010\\n\\004B\"\n                + \"ENZ\\020\\001\\022\\017\\n\\013LAMBORGHINI\\020\\002\\022\\013\\n\\007DASAUTO\\020\\003B3\\n#c\"\n                + \"om.lyncc.netty.codec.protobuf.demoB\\014Rich\" + \"ManProto\" };\n        com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner = new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() {\n            public com.google.protobuf.ExtensionRegistry assignDescriptors(\n                    com.google.protobuf.Descriptors.FileDescriptor root) {\n                descriptor = root;\n                return null;\n            }\n        };\n        com.google.protobuf.Descriptors.FileDescriptor.internalBuildGeneratedFileFrom(descriptorData,\n                new com.google.protobuf.Descriptors.FileDescriptor[] {}, assigner);\n        internal_static_netty_RichMan_descriptor = getDescriptor().getMessageTypes().get(0);\n        internal_static_netty_RichMan_fieldAccessorTable = new com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n                internal_static_netty_RichMan_descriptor, new java.lang.String[] { \"Id\", \"Name\", \"Email\", \"Cars\", });\n        internal_static_netty_RichMan_Car_descriptor = internal_static_netty_RichMan_descriptor.getNestedTypes().get(0);\n        internal_static_netty_RichMan_Car_fieldAccessorTable = new com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n                internal_static_netty_RichMan_Car_descriptor, new java.lang.String[] { \"Name\", \"Type\", });\n    }\n\n    // @@protoc_insertion_point(outer_class_scope)\n}\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/component/channelhandler/BaseClient.java",
    "content": "package com.lyncc.netty.component.channelhandler;\r\n\r\nimport io.netty.bootstrap.Bootstrap;\r\nimport io.netty.channel.ChannelFuture;\r\nimport io.netty.channel.ChannelInitializer;\r\nimport io.netty.channel.ChannelOption;\r\nimport io.netty.channel.ChannelPipeline;\r\nimport io.netty.channel.EventLoopGroup;\r\nimport io.netty.channel.nio.NioEventLoopGroup;\r\nimport io.netty.channel.socket.SocketChannel;\r\nimport io.netty.channel.socket.nio.NioSocketChannel;\r\nimport io.netty.handler.codec.string.StringDecoder;\r\nimport io.netty.handler.codec.string.StringEncoder;\r\n\r\npublic class BaseClient {\r\n    \r\n    static final String HOST = System.getProperty(\"host\", \"127.0.0.1\");\r\n    static final int PORT = Integer.parseInt(System.getProperty(\"port\", \"8080\"));\r\n    static final int SIZE = Integer.parseInt(System.getProperty(\"size\", \"256\"));\r\n\r\n    public static void main(String[] args) throws Exception {\r\n\r\n        // Configure the client.\r\n        EventLoopGroup group = new NioEventLoopGroup();\r\n        try {\r\n            Bootstrap b = new Bootstrap();\r\n            b.group(group)\r\n             .channel(NioSocketChannel.class)\r\n             .option(ChannelOption.TCP_NODELAY, true)\r\n             .handler(new ChannelInitializer<SocketChannel>() {\r\n                 @Override\r\n                 public void initChannel(SocketChannel ch) throws Exception {\r\n                     ChannelPipeline p = ch.pipeline();\r\n                     p.addLast(\"decoder\", new StringDecoder());\r\n                     p.addLast(\"encoder\", new StringEncoder());\r\n                     p.addLast(new BaseClient1Handler());\r\n                     p.addLast(new BaseClient2Handler());\r\n                 }\r\n             });\r\n\r\n            ChannelFuture future = b.connect(HOST, PORT).sync();\r\n            future.channel().writeAndFlush(\"Hello Netty Server ,I am a common client\");\r\n            future.channel().closeFuture().sync();\r\n        } finally {\r\n            group.shutdownGracefully();\r\n        }\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/component/channelhandler/BaseClient1Handler.java",
    "content": "package com.lyncc.netty.component.channelhandler;\r\n\r\nimport io.netty.channel.ChannelHandlerContext;\r\nimport io.netty.channel.ChannelInboundHandlerAdapter;\r\n\r\n/**\r\n * \r\n * @author bazingaLyncc\r\n * 描述：客户端的第一个自定义的inbound处理器\r\n * 时间  2016年5月3日\r\n */\r\npublic class BaseClient1Handler extends ChannelInboundHandlerAdapter{\r\n    \r\n    @Override\r\n    public void channelActive(ChannelHandlerContext ctx) throws Exception {\r\n        System.out.println(\"BaseClient1Handler channelActive\");\r\n        ctx.fireChannelActive();\r\n    }\r\n    \r\n    @Override\r\n    public void channelInactive(ChannelHandlerContext ctx) throws Exception {\r\n        System.out.println(\"BaseClient1Handler channelInactive\");\r\n    }\r\n    \r\n\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/component/channelhandler/BaseClient2Handler.java",
    "content": "package com.lyncc.netty.component.channelhandler;\r\n\r\nimport io.netty.channel.ChannelHandlerContext;\r\nimport io.netty.channel.ChannelInboundHandlerAdapter;\r\n\r\n/**\r\n * \r\n * @author bazingaLyncc\r\n * 描述：客户端的第二个自定义的inbound处理器\r\n * 时间  2016年5月3日\r\n */\r\npublic class BaseClient2Handler extends ChannelInboundHandlerAdapter{\r\n    \r\n    @Override\r\n    public void channelActive(ChannelHandlerContext ctx) throws Exception {\r\n        System.out.println(\"BaseClient2Handler Active\");\r\n    }\r\n   \r\n\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/component/channelhandler/BaseServer.java",
    "content": "package com.lyncc.netty.component.channelhandler;\r\n\r\nimport io.netty.bootstrap.ServerBootstrap;\r\nimport io.netty.channel.ChannelFuture;\r\nimport io.netty.channel.ChannelInitializer;\r\nimport io.netty.channel.ChannelOption;\r\nimport io.netty.channel.EventLoopGroup;\r\nimport io.netty.channel.nio.NioEventLoopGroup;\r\nimport io.netty.channel.socket.SocketChannel;\r\nimport io.netty.channel.socket.nio.NioServerSocketChannel;\r\nimport io.netty.handler.codec.string.StringDecoder;\r\nimport io.netty.handler.codec.string.StringEncoder;\r\n\r\nimport java.net.InetSocketAddress;\r\n\r\npublic class BaseServer {\r\n\r\n    private int port;\r\n    \r\n    public BaseServer(int port) {\r\n        this.port = port;\r\n    }\r\n    \r\n    public void start(){\r\n        EventLoopGroup bossGroup = new NioEventLoopGroup(1);\r\n        EventLoopGroup workerGroup = new NioEventLoopGroup();\r\n        try {\r\n            ServerBootstrap sbs = new ServerBootstrap().group(bossGroup,workerGroup).channel(NioServerSocketChannel.class).localAddress(new InetSocketAddress(port))\r\n                    .childHandler(new ChannelInitializer<SocketChannel>() {\r\n                        \r\n                        protected void initChannel(SocketChannel ch) throws Exception {\r\n//                            ch.pipeline().addLast(\"framer\", new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));\r\n                            ch.pipeline().addLast(\"decoder\", new StringDecoder());\r\n                            ch.pipeline().addLast(\"encoder\", new StringEncoder());\r\n                            ch.pipeline().addLast(new BaseServerHandler());\r\n                        };\r\n                        \r\n                    }).option(ChannelOption.SO_BACKLOG, 128)   \r\n                    .childOption(ChannelOption.SO_KEEPALIVE, true);\r\n             // 绑定端口，开始接收进来的连接\r\n             ChannelFuture future = sbs.bind(port).sync();  \r\n             \r\n             System.out.println(\"Server start listen at \" + port );\r\n             future.channel().closeFuture().sync();\r\n        } catch (Exception e) {\r\n            bossGroup.shutdownGracefully();\r\n            workerGroup.shutdownGracefully();\r\n        }\r\n    }\r\n    \r\n    public static void main(String[] args) throws Exception {\r\n        int port;\r\n        if (args.length > 0) {\r\n            port = Integer.parseInt(args[0]);\r\n        } else {\r\n            port = 8080;\r\n        }\r\n        new BaseServer(port).start();\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/component/channelhandler/BaseServerHandler.java",
    "content": "package com.lyncc.netty.component.channelhandler;\r\n\r\nimport io.netty.buffer.Unpooled;\r\nimport io.netty.channel.ChannelHandlerContext;\r\nimport io.netty.channel.ChannelInboundHandlerAdapter;\r\nimport io.netty.util.CharsetUtil;\r\n\r\npublic class BaseServerHandler extends ChannelInboundHandlerAdapter{\r\n    \r\n    \r\n    @Override\r\n    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {\r\n        System.out.println(\"server channelRead..\");\r\n        System.out.println(ctx.channel().remoteAddress()+\"->Server :\"+ msg.toString());\r\n        ctx.writeAndFlush(Unpooled.copiedBuffer(\"hello my name is lyncc\", CharsetUtil.UTF_8));\r\n    }\r\n    \r\n    \r\n    @Override\r\n    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {\r\n        cause.printStackTrace();\r\n        ctx.close();\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/component/simplehandler/BaseClient.java",
    "content": "package com.lyncc.netty.component.simplehandler;\r\n\r\nimport io.netty.bootstrap.Bootstrap;\r\nimport io.netty.channel.ChannelFuture;\r\nimport io.netty.channel.ChannelInitializer;\r\nimport io.netty.channel.ChannelOption;\r\nimport io.netty.channel.ChannelPipeline;\r\nimport io.netty.channel.EventLoopGroup;\r\nimport io.netty.channel.nio.NioEventLoopGroup;\r\nimport io.netty.channel.socket.SocketChannel;\r\nimport io.netty.channel.socket.nio.NioSocketChannel;\r\nimport io.netty.handler.codec.string.StringDecoder;\r\nimport io.netty.handler.codec.string.StringEncoder;\r\n\r\npublic class BaseClient {\r\n    \r\n    static final String HOST = System.getProperty(\"host\", \"127.0.0.1\");\r\n    static final int PORT = Integer.parseInt(System.getProperty(\"port\", \"8080\"));\r\n    static final int SIZE = Integer.parseInt(System.getProperty(\"size\", \"256\"));\r\n\r\n    public static void main(String[] args) throws Exception {\r\n\r\n        // Configure the client.\r\n        EventLoopGroup group = new NioEventLoopGroup();\r\n        try {\r\n            Bootstrap b = new Bootstrap();\r\n            b.group(group)\r\n             .channel(NioSocketChannel.class)\r\n             .option(ChannelOption.TCP_NODELAY, true)\r\n             .handler(new ChannelInitializer<SocketChannel>() {\r\n                 @Override\r\n                 public void initChannel(SocketChannel ch) throws Exception {\r\n                     ChannelPipeline p = ch.pipeline();\r\n                     p.addLast(\"decoder\", new StringDecoder());\r\n                     p.addLast(\"encoder\", new StringEncoder());\r\n                     p.addLast(new BaseClientHandler());\r\n                 }\r\n             });\r\n\r\n            ChannelFuture future = b.connect(HOST, PORT).sync();\r\n            future.channel().writeAndFlush(\"Hello Netty Server ,I am a common client\");\r\n            future.channel().closeFuture().sync();\r\n        } finally {\r\n            group.shutdownGracefully();\r\n        }\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/component/simplehandler/BaseClientHandler.java",
    "content": "package com.lyncc.netty.component.simplehandler;\r\n\r\nimport io.netty.channel.ChannelHandlerContext;\r\nimport io.netty.channel.SimpleChannelInboundHandler;\r\n\r\npublic class BaseClientHandler extends SimpleChannelInboundHandler<String>{\r\n    \r\n    @Override\r\n    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {\r\n        System.out.println(\"Client channelRead0 received:\" + msg);\r\n    }\r\n    \r\n//    @Override\r\n//    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {\r\n//        System.out.println(\"Client channelRead received:\" + msg);\r\n//        \r\n//    }\r\n  \r\n     @Override\r\n     public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {\r\n         cause.printStackTrace();\r\n         ctx.close();\r\n     }\r\n   \r\n\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/component/simplehandler/BaseServer.java",
    "content": "package com.lyncc.netty.component.simplehandler;\r\n\r\nimport io.netty.bootstrap.ServerBootstrap;\r\nimport io.netty.channel.ChannelFuture;\r\nimport io.netty.channel.ChannelInitializer;\r\nimport io.netty.channel.ChannelOption;\r\nimport io.netty.channel.EventLoopGroup;\r\nimport io.netty.channel.nio.NioEventLoopGroup;\r\nimport io.netty.channel.socket.SocketChannel;\r\nimport io.netty.channel.socket.nio.NioServerSocketChannel;\r\nimport io.netty.handler.codec.string.StringDecoder;\r\nimport io.netty.handler.codec.string.StringEncoder;\r\n\r\nimport java.net.InetSocketAddress;\r\n\r\npublic class BaseServer {\r\n\r\n    private int port;\r\n    \r\n    public BaseServer(int port) {\r\n        this.port = port;\r\n    }\r\n    \r\n    public void start(){\r\n        EventLoopGroup bossGroup = new NioEventLoopGroup(1);\r\n        EventLoopGroup workerGroup = new NioEventLoopGroup();\r\n        try {\r\n            ServerBootstrap sbs = new ServerBootstrap().group(bossGroup,workerGroup).channel(NioServerSocketChannel.class).localAddress(new InetSocketAddress(port))\r\n                    .childHandler(new ChannelInitializer<SocketChannel>() {\r\n                        \r\n                        protected void initChannel(SocketChannel ch) throws Exception {\r\n//                            ch.pipeline().addLast(\"framer\", new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));\r\n                            ch.pipeline().addLast(\"decoder\", new StringDecoder());\r\n                            ch.pipeline().addLast(\"encoder\", new StringEncoder());\r\n                            ch.pipeline().addLast(new BaseServerHandler());\r\n                        };\r\n                        \r\n                    }).option(ChannelOption.SO_BACKLOG, 128)   \r\n                    .childOption(ChannelOption.SO_KEEPALIVE, true);\r\n             // 绑定端口，开始接收进来的连接\r\n             ChannelFuture future = sbs.bind(port).sync();  \r\n             \r\n             System.out.println(\"Server start listen at \" + port );\r\n             future.channel().closeFuture().sync();\r\n        } catch (Exception e) {\r\n            bossGroup.shutdownGracefully();\r\n            workerGroup.shutdownGracefully();\r\n        }\r\n    }\r\n    \r\n    public static void main(String[] args) throws Exception {\r\n        int port;\r\n        if (args.length > 0) {\r\n            port = Integer.parseInt(args[0]);\r\n        } else {\r\n            port = 8080;\r\n        }\r\n        new BaseServer(port).start();\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/component/simplehandler/BaseServerHandler.java",
    "content": "package com.lyncc.netty.component.simplehandler;\r\n\r\nimport io.netty.buffer.Unpooled;\r\nimport io.netty.channel.ChannelHandlerContext;\r\nimport io.netty.channel.ChannelInboundHandlerAdapter;\r\nimport io.netty.util.CharsetUtil;\r\n\r\npublic class BaseServerHandler extends ChannelInboundHandlerAdapter{\r\n    \r\n    \r\n    @Override\r\n    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {\r\n        System.out.println(\"server channelRead..\");\r\n        System.out.println(ctx.channel().remoteAddress()+\"->Server :\"+ msg.toString());\r\n        ctx.writeAndFlush(Unpooled.copiedBuffer(\"hello my name is lyncc\", CharsetUtil.UTF_8));\r\n    }\r\n    \r\n    \r\n    @Override\r\n    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {\r\n        cause.printStackTrace();\r\n        ctx.close();\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/concept/HelloWorldConcept.java",
    "content": "package com.lyncc.netty.concept;\r\n\r\n/**\r\n * \r\n * @author Bazingalyncc\r\n * 描述：\r\n * 时间  2016年4月29日\r\n */\r\npublic class HelloWorldConcept {\r\n    \r\n    /**\r\n     * \r\n     * \r\n     * \r\n     * \r\n     *                   ________________________                                 __________________________\r\n     *                  |                        |                               |                          |    \r\n     *                  |   <-----Inbound-----   |                               |   ---inbound------- >    |   ________\r\n     *                  |   _____        ______  |                               |    _______      ____     |  |        |\r\n     *      _______     |  |     |       |    |  |                               |    |     |     |    |    |  |        |  \r\n     *     |       |    |  |  ②  |       |  ③ |  |      ___________________      |    |  ⑤  |     |  ⑥ |    |  |        |\r\n     *     |       |    |  |_____|       |____|  |     |                   |     |    |_____|     |____|    |  |        |     \r\n     *     |client |----|-------______-----------|-----|      network      |-----|--------------------------|--| server |\r\n     *     |       |    |       |     |          |     |___________________|     |          ______          |  |        |\r\n     *     |       |    |       |  ①  |          |                               |          |     |         |  |        |         \r\n     *     |       |    |       |_____|          |                               |          |  ④  |         |  |________|\r\n     *     |       |    |                        |                               |          |_____|         |\r\n     *     |_______|    |   -----Outbound--->    |                               |    <-----outbound----    | \r\n     *                  |___ChannelPipeline______|                               |______ChannelPipeline_____| \r\n     *                                                                               \r\n     *  ①：StringEncoder继承于MessageToMessageEncoder，而MessageToMessageEncoder又继承于ChannelOutboundHandlerAdapter\r\n     *  ②：HelloWorldClientHandler.java\r\n     *  ③：StringDecoder继承于MessageToMessageDecoder，而MessageToMessageDecoder又继承于ChannelInboundHandlerAdapter\r\n     *  ④：StringEncoder 编码器\r\n     *  ⑤：StringDecoder 解码器\r\n     *  ⑥：HelloWorldServerHandler.java\r\n     *  \r\n     * \r\n     * \r\n     */\r\n\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/heartbeat/BaseClient.java",
    "content": "package com.lyncc.netty.heartbeat;\r\n\r\nimport io.netty.bootstrap.Bootstrap;\r\nimport io.netty.channel.ChannelFuture;\r\nimport io.netty.channel.ChannelInitializer;\r\nimport io.netty.channel.ChannelOption;\r\nimport io.netty.channel.ChannelPipeline;\r\nimport io.netty.channel.EventLoopGroup;\r\nimport io.netty.channel.nio.NioEventLoopGroup;\r\nimport io.netty.channel.socket.SocketChannel;\r\nimport io.netty.channel.socket.nio.NioSocketChannel;\r\nimport io.netty.handler.codec.string.StringDecoder;\r\nimport io.netty.handler.codec.string.StringEncoder;\r\nimport io.netty.handler.timeout.IdleStateHandler;\r\n\r\nimport java.util.concurrent.TimeUnit;\r\n\r\npublic class BaseClient {\r\n\r\n    public void connect(int port, String host) throws Exception {\r\n        ChannelFuture future = null;\r\n        // Configure the client.\r\n        EventLoopGroup group = new NioEventLoopGroup();\r\n        Bootstrap b = new Bootstrap().group(group).channel(NioSocketChannel.class)\r\n                .option(ChannelOption.TCP_NODELAY, true).handler(new ChannelInitializer<SocketChannel>() {\r\n                    @Override\r\n                    public void initChannel(SocketChannel ch) throws Exception {\r\n                        ChannelPipeline p = ch.pipeline();\r\n                        p.addLast(\"decoder\", new StringDecoder());\r\n                        p.addLast(\"encoder\", new StringEncoder());\r\n                        p.addLast(\"ping\", new IdleStateHandler(0, 4, 0, TimeUnit.SECONDS));\r\n                        p.addLast(new BaseClientHandler());\r\n                    }\r\n                });\r\n\r\n        try {\r\n            future = b.connect(host, port).sync();\r\n            future.channel().writeAndFlush(\"Hello Netty Server ,I am a common client\");\r\n            future.channel().closeFuture().sync();\r\n        } finally {\r\n//            group.shutdownGracefully();\r\n            if (null != future) {\r\n                if (future.channel() != null && future.channel().isOpen()) {\r\n                    future.channel().close();\r\n                }\r\n            }\r\n            System.out.println(\"准备重连\");\r\n            connect(port, host);\r\n            System.out.println(\"重连成功\");\r\n        }\r\n    }\r\n\r\n    /**\r\n     * @param args\r\n     * @throws Exception\r\n     */\r\n    public static void main(String[] args) throws Exception {\r\n        int port = 8080;\r\n        if (args != null && args.length > 0) {\r\n            try {\r\n                port = Integer.valueOf(args[0]);\r\n            } catch (NumberFormatException e) {\r\n                // 采用默认值\r\n            }\r\n        }\r\n        new BaseClient().connect(port, \"127.0.0.1\");\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/heartbeat/BaseClientHandler.java",
    "content": "package com.lyncc.netty.heartbeat;\r\n\r\nimport io.netty.buffer.ByteBuf;\r\nimport io.netty.buffer.Unpooled;\r\nimport io.netty.channel.ChannelHandlerContext;\r\nimport io.netty.channel.ChannelInboundHandlerAdapter;\r\nimport io.netty.handler.timeout.IdleState;\r\nimport io.netty.handler.timeout.IdleStateEvent;\r\nimport io.netty.util.CharsetUtil;\r\nimport io.netty.util.ReferenceCountUtil;\r\n\r\nimport java.util.Date;\r\n\r\n/**\r\n * \r\n * @author bazingaLyncc 描述：客户端的第一个自定义的inbound处理器 时间 2016年5月3日\r\n */\r\npublic class BaseClientHandler extends ChannelInboundHandlerAdapter {\r\n\r\n    private static final ByteBuf HEARTBEAT_SEQUENCE = Unpooled.unreleasableBuffer(Unpooled.copiedBuffer(\"Heartbeat\",\r\n            CharsetUtil.UTF_8));\r\n    \r\n    private static final int TRY_TIMES = 3;\r\n    \r\n    private int currentTime = 0;\r\n    \r\n    @Override\r\n    public void channelActive(ChannelHandlerContext ctx) throws Exception {\r\n        System.out.println(\"启动时间是：\"+new Date());\r\n        System.out.println(\"BaseClient1Handler channelActive\");\r\n        ctx.fireChannelActive();\r\n    }\r\n\r\n    @Override\r\n    public void channelInactive(ChannelHandlerContext ctx) throws Exception {\r\n        System.out.println(\"BaseClient1Handler channelInactive\");\r\n    }\r\n\r\n    @Override\r\n    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {\r\n        System.out.println(\"触发时间：\"+new Date());\r\n        if (evt instanceof IdleStateEvent) {\r\n            IdleStateEvent event = (IdleStateEvent) evt;\r\n            if (event.state() == IdleState.WRITER_IDLE) {\r\n                if(currentTime <= TRY_TIMES){\r\n                    System.out.println(\"currentTime:\"+currentTime);\r\n                    currentTime++;\r\n                    ctx.channel().writeAndFlush(HEARTBEAT_SEQUENCE.duplicate());\r\n                }\r\n            }\r\n        }\r\n    }\r\n\r\n    @Override\r\n    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {\r\n        String message = (String) msg;\r\n        System.out.println(message);\r\n        if (message.equals(\"Heartbeat\")) {\r\n            ctx.write(\"has read message from server\");\r\n            ctx.flush();\r\n        }\r\n        ReferenceCountUtil.release(msg);\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/heartbeat/BaseServer.java",
    "content": "package com.lyncc.netty.heartbeat;\r\n\r\nimport io.netty.bootstrap.ServerBootstrap;\r\nimport io.netty.channel.ChannelFuture;\r\nimport io.netty.channel.ChannelInitializer;\r\nimport io.netty.channel.ChannelOption;\r\nimport io.netty.channel.EventLoopGroup;\r\nimport io.netty.channel.nio.NioEventLoopGroup;\r\nimport io.netty.channel.socket.SocketChannel;\r\nimport io.netty.channel.socket.nio.NioServerSocketChannel;\r\nimport io.netty.handler.codec.string.StringDecoder;\r\nimport io.netty.handler.codec.string.StringEncoder;\r\nimport io.netty.handler.timeout.IdleStateHandler;\r\n\r\nimport java.net.InetSocketAddress;\r\nimport java.util.concurrent.TimeUnit;\r\n\r\npublic class BaseServer {\r\n\r\n    private int port;\r\n    \r\n    public BaseServer(int port) {\r\n        this.port = port;\r\n    }\r\n    \r\n    public void start(){\r\n        EventLoopGroup bossGroup = new NioEventLoopGroup(1);\r\n        EventLoopGroup workerGroup = new NioEventLoopGroup();\r\n        try {\r\n            ServerBootstrap sbs = new ServerBootstrap().group(bossGroup,workerGroup).channel(NioServerSocketChannel.class).localAddress(new InetSocketAddress(port))\r\n                    .childHandler(new ChannelInitializer<SocketChannel>() {\r\n                        \r\n                        private static final int READ_IDEL_TIME_OUT = 5; // 读超时\r\n                        private static final int WRITE_IDEL_TIME_OUT = 0;// 写超时\r\n                        private static final int ALL_IDEL_TIME_OUT = 0; // 所有超时\r\n                        \r\n                        protected void initChannel(SocketChannel ch) throws Exception {\r\n                            ch.pipeline().addLast(new IdleStateHandler(READ_IDEL_TIME_OUT,\r\n                                    WRITE_IDEL_TIME_OUT, ALL_IDEL_TIME_OUT, TimeUnit.SECONDS));\r\n                            ch.pipeline().addLast(\"decoder\", new StringDecoder());\r\n                            ch.pipeline().addLast(\"encoder\", new StringEncoder());\r\n                            ch.pipeline().addLast(new BaseServerHandler());\r\n                        };\r\n                        \r\n                    }).option(ChannelOption.SO_BACKLOG, 128)   \r\n                    .childOption(ChannelOption.SO_KEEPALIVE, true);\r\n             // 绑定端口，开始接收进来的连接\r\n             ChannelFuture future = sbs.bind(port).sync();  \r\n             \r\n             System.out.println(\"Server start listen at \" + port );\r\n             future.channel().closeFuture().sync();\r\n        } catch (Exception e) {\r\n            bossGroup.shutdownGracefully();\r\n            workerGroup.shutdownGracefully();\r\n        }\r\n    }\r\n    \r\n    public static void main(String[] args) throws Exception {\r\n        int port;\r\n        if (args.length > 0) {\r\n            port = Integer.parseInt(args[0]);\r\n        } else {\r\n            port = 8080;\r\n        }\r\n        new BaseServer(port).start();\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/heartbeat/BaseServerHandler.java",
    "content": "package com.lyncc.netty.heartbeat;\r\n\r\nimport io.netty.channel.ChannelHandlerContext;\r\nimport io.netty.channel.ChannelInboundHandlerAdapter;\r\nimport io.netty.handler.timeout.IdleState;\r\nimport io.netty.handler.timeout.IdleStateEvent;\r\n\r\npublic class BaseServerHandler extends ChannelInboundHandlerAdapter{\r\n    \r\n    private int loss_connect_time = 0;\r\n    \r\n    @Override\r\n    public void userEventTriggered(ChannelHandlerContext ctx, Object evt)\r\n            throws Exception {\r\n        System.out.println(\"hehehehe\");\r\n        if (evt instanceof IdleStateEvent) {\r\n            IdleStateEvent event = (IdleStateEvent) evt;\r\n            if (event.state() == IdleState.READER_IDLE) {\r\n                loss_connect_time++;\r\n                System.out.println(\"10 秒没有接收到客户端的信息了\");\r\n                if(loss_connect_time > 2 ){\r\n                    ctx.channel().close();\r\n                }\r\n            }  \r\n        } else {\r\n            super.userEventTriggered(ctx, evt);\r\n        }\r\n    }\r\n    \r\n    @Override\r\n    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {\r\n        System.out.println(\"server channelRead..\");\r\n        System.out.println(ctx.channel().remoteAddress()+\"->Server :\"+ msg.toString());\r\n    }\r\n    \r\n    \r\n    @Override\r\n    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {\r\n        cause.printStackTrace();\r\n        ctx.close();\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/heartbeat2/AskMsg.java",
    "content": "package com.lyncc.netty.heartbeat2;\r\n\r\npublic class AskMsg extends BaseMsg {\r\n    \r\n    public AskMsg() {\r\n        super();\r\n        setType(MsgType.ASK);\r\n    }\r\n    \r\n    private AskParams params;\r\n\r\n    public AskParams getParams() {\r\n        return params;\r\n    }\r\n\r\n    public void setParams(AskParams params) {\r\n        this.params = params;\r\n    }\r\n    \r\n\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/heartbeat2/AskParams.java",
    "content": "package com.lyncc.netty.heartbeat2;\r\n\r\nimport java.io.Serializable;\r\n\r\npublic class AskParams implements Serializable{\r\n\r\n    /**\r\n     * \r\n     */\r\n    private static final long serialVersionUID = 1L;\r\n    \r\n    private String auth;\r\n\r\n    public String getAuth() {\r\n        return auth;\r\n    }\r\n\r\n    public void setAuth(String auth) {\r\n        this.auth = auth;\r\n    }\r\n    \r\n\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/heartbeat2/BaseMsg.java",
    "content": "package com.lyncc.netty.heartbeat2;\r\n\r\nimport java.io.Serializable;\r\n\r\npublic abstract class BaseMsg implements Serializable {\r\n\r\n    /**\r\n     * \r\n     */\r\n    private static final long serialVersionUID = 1L;\r\n    \r\n    private MsgType type;\r\n    \r\n    private String clientId;\r\n    \r\n    public BaseMsg() {\r\n        this.clientId = Constants.getClientId();\r\n    }\r\n\r\n    public MsgType getType() {\r\n        return type;\r\n    }\r\n\r\n    public void setType(MsgType type) {\r\n        this.type = type;\r\n    }\r\n\r\n    public String getClientId() {\r\n        return clientId;\r\n    }\r\n\r\n    public void setClientId(String clientId) {\r\n        this.clientId = clientId;\r\n    }\r\n    \r\n\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/heartbeat2/Constants.java",
    "content": "package com.lyncc.netty.heartbeat2;\r\n\r\npublic class Constants {\r\n    \r\n    private static String clientId;\r\n\r\n    public static String getClientId() {\r\n        return clientId;\r\n    }\r\n\r\n    public static void setClientId(String clientId) {\r\n        Constants.clientId = clientId;\r\n    }\r\n    \r\n\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/heartbeat2/LoginMsg.java",
    "content": "package com.lyncc.netty.heartbeat2;\r\n\r\npublic class LoginMsg extends BaseMsg {\r\n    \r\n\r\n    private String userName;\r\n    \r\n    private String password;\r\n    \r\n    public LoginMsg() {\r\n        super();\r\n        setType(MsgType.LOGIN);\r\n    }\r\n\r\n    public String getUserName() {\r\n        return userName;\r\n    }\r\n\r\n    public void setUserName(String userName) {\r\n        this.userName = userName;\r\n    }\r\n\r\n    public String getPassword() {\r\n        return password;\r\n    }\r\n\r\n    public void setPassword(String password) {\r\n        this.password = password;\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/heartbeat2/MsgType.java",
    "content": "package com.lyncc.netty.heartbeat2;\r\n\r\npublic enum MsgType {\r\n    \r\n    PING,ASK,REPLY,LOGIN\r\n\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/heartbeat2/NettyChannelMap.java",
    "content": "package com.lyncc.netty.heartbeat2;\r\n\r\nimport io.netty.channel.Channel;\r\nimport io.netty.channel.socket.SocketChannel;\r\n\r\nimport java.util.Map;\r\nimport java.util.concurrent.ConcurrentHashMap;\r\n\r\npublic class NettyChannelMap {\r\n    \r\n    private static Map<String,SocketChannel> map = new ConcurrentHashMap<String,SocketChannel>();\r\n    \r\n    public static void add(String clientId,SocketChannel socketChannel){\r\n        map.put(clientId, socketChannel);\r\n    }\r\n    \r\n    public static Channel get(String clientId){\r\n        return map.get(clientId);\r\n     }\r\n\r\n    public static void remove(SocketChannel socketChannel){\r\n        \r\n        for(Map.Entry<String,SocketChannel> entry : map.entrySet()){\r\n            if(entry.getValue() == socketChannel){\r\n                map.remove(entry.getKey());\r\n            }\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/heartbeat2/NettyClientBootstrap.java",
    "content": "package com.lyncc.netty.heartbeat2;\r\n\r\nimport io.netty.bootstrap.Bootstrap;\r\nimport io.netty.channel.ChannelFuture;\r\nimport io.netty.channel.ChannelInitializer;\r\nimport io.netty.channel.ChannelOption;\r\nimport io.netty.channel.EventLoopGroup;\r\nimport io.netty.channel.nio.NioEventLoopGroup;\r\nimport io.netty.channel.socket.SocketChannel;\r\nimport io.netty.channel.socket.nio.NioSocketChannel;\r\nimport io.netty.handler.codec.serialization.ClassResolvers;\r\nimport io.netty.handler.codec.serialization.ObjectDecoder;\r\nimport io.netty.handler.codec.serialization.ObjectEncoder;\r\nimport io.netty.handler.timeout.IdleStateHandler;\r\nimport io.netty.util.concurrent.DefaultEventExecutorGroup;\r\nimport io.netty.util.concurrent.EventExecutorGroup;\r\n\r\nimport java.util.concurrent.TimeUnit;\r\n\r\npublic class NettyClientBootstrap {\r\n\r\n    private int port;\r\n\r\n    private String host;\r\n\r\n    private SocketChannel socketChannel;\r\n\r\n    private static final EventExecutorGroup group = new DefaultEventExecutorGroup(20);\r\n\r\n    public NettyClientBootstrap(int port, String host) throws InterruptedException {\r\n        this.port = port;\r\n        this.host = host;\r\n        start();\r\n    }\r\n\r\n    private void start() throws InterruptedException {\r\n        EventLoopGroup eventLoopGroup = new NioEventLoopGroup();\r\n        Bootstrap bootstrap = new Bootstrap();\r\n        bootstrap.channel(NioSocketChannel.class);\r\n        bootstrap.option(ChannelOption.SO_KEEPALIVE, true);\r\n        bootstrap.group(eventLoopGroup);\r\n        bootstrap.remoteAddress(host, port);\r\n        bootstrap.handler(new ChannelInitializer<SocketChannel>() {\r\n            @Override\r\n            protected void initChannel(SocketChannel socketChannel) throws Exception {\r\n                socketChannel.pipeline().addLast(new IdleStateHandler(20, 10, 0));\r\n                socketChannel.pipeline().addLast(new ObjectEncoder());\r\n                socketChannel.pipeline().addLast(new ObjectDecoder(ClassResolvers.cacheDisabled(null)));\r\n                socketChannel.pipeline().addLast(new NettyClientHandler());\r\n            }\r\n        });\r\n        ChannelFuture future = bootstrap.connect(host, port).sync();\r\n        if (future.isSuccess()) {\r\n            socketChannel = (SocketChannel) future.channel();\r\n            System.out.println(\"connect server  成功---------\");\r\n        }\r\n    }\r\n\r\n    public static void main(String[] args) throws InterruptedException {\r\n        Constants.setClientId(\"001\");\r\n        NettyClientBootstrap bootstrap = new NettyClientBootstrap(18080, \"localhost\");\r\n\r\n        LoginMsg loginMsg = new LoginMsg();\r\n        loginMsg.setPassword(\"yao\");\r\n        loginMsg.setUserName(\"robin\");\r\n        bootstrap.socketChannel.writeAndFlush(loginMsg);\r\n        while (true) {\r\n            TimeUnit.SECONDS.sleep(3);\r\n            AskMsg askMsg = new AskMsg();\r\n            AskParams askParams = new AskParams();\r\n            askParams.setAuth(\"authToken\");\r\n            askMsg.setParams(askParams);\r\n            bootstrap.socketChannel.writeAndFlush(askMsg);\r\n        }\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/heartbeat2/NettyClientHandler.java",
    "content": "package com.lyncc.netty.heartbeat2;\r\n\r\nimport io.netty.channel.Channel;\r\nimport io.netty.channel.ChannelHandlerContext;\r\nimport io.netty.channel.SimpleChannelInboundHandler;\r\nimport io.netty.handler.timeout.IdleStateEvent;\r\nimport io.netty.util.ReferenceCountUtil;\r\n\r\npublic class NettyClientHandler extends SimpleChannelInboundHandler<BaseMsg> {\r\n    //利用写空闲发送心跳检测消息\r\n    @Override\r\n    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {\r\n        if (evt instanceof IdleStateEvent) {\r\n            IdleStateEvent e = (IdleStateEvent) evt;\r\n            switch (e.state()) {\r\n                case WRITER_IDLE:\r\n                    PingMsg pingMsg=new PingMsg();\r\n                    ctx.writeAndFlush(pingMsg);\r\n                    System.out.println(\"send ping to server----------\");\r\n                    break;\r\n                default:\r\n                    break;\r\n            }\r\n        }\r\n    }\r\n    @Override\r\n    protected void channelRead0(ChannelHandlerContext channelHandlerContext, BaseMsg baseMsg) throws Exception {\r\n        MsgType msgType=baseMsg.getType();\r\n        switch (msgType){\r\n            case LOGIN:{\r\n                //向服务器发起登录\r\n                LoginMsg loginMsg=new LoginMsg();\r\n                loginMsg.setPassword(\"yao\");\r\n                loginMsg.setUserName(\"robin\");\r\n                channelHandlerContext.writeAndFlush(loginMsg);\r\n            }break;\r\n            case PING:{\r\n                System.out.println(\"receive ping from server----------\");\r\n            }break;\r\n            case ASK:{\r\n                ReplyClientBody replyClientBody=new ReplyClientBody(\"client info **** !!!\");\r\n                ReplyMsg replyMsg=new ReplyMsg();\r\n                replyMsg.setBody(replyClientBody);\r\n                channelHandlerContext.writeAndFlush(replyMsg);\r\n            }break;\r\n            case REPLY:{\r\n                ReplyMsg replyMsg=(ReplyMsg)baseMsg;\r\n                ReplyServerBody replyServerBody=(ReplyServerBody)replyMsg.getBody();\r\n                System.out.println(\"receive client msg: \"+replyServerBody.getServerInfo());\r\n            }\r\n            default:break;\r\n        }\r\n        ReferenceCountUtil.release(msgType);\r\n    }\r\n    \r\n    @Override\r\n    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {\r\n        Channel incoming = ctx.channel();\r\n        System.out.println(\"SimpleChatClient:\"+incoming.remoteAddress()+\"异常\");\r\n        cause.printStackTrace();\r\n        ctx.close();\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/heartbeat2/NettyServerBootstrap.java",
    "content": "package com.lyncc.netty.heartbeat2;\r\n\r\nimport io.netty.bootstrap.ServerBootstrap;\r\nimport io.netty.channel.ChannelFuture;\r\nimport io.netty.channel.ChannelInitializer;\r\nimport io.netty.channel.ChannelOption;\r\nimport io.netty.channel.ChannelPipeline;\r\nimport io.netty.channel.EventLoopGroup;\r\nimport io.netty.channel.nio.NioEventLoopGroup;\r\nimport io.netty.channel.socket.SocketChannel;\r\nimport io.netty.channel.socket.nio.NioServerSocketChannel;\r\nimport io.netty.handler.codec.serialization.ClassResolvers;\r\nimport io.netty.handler.codec.serialization.ObjectDecoder;\r\nimport io.netty.handler.codec.serialization.ObjectEncoder;\r\nimport io.netty.handler.logging.LogLevel;\r\nimport io.netty.handler.logging.LoggingHandler;\r\n\r\nimport java.util.concurrent.TimeUnit;\r\n\r\npublic class NettyServerBootstrap {\r\n\r\n    private int port;\r\n\r\n    private SocketChannel socketChannel;\r\n\r\n    public NettyServerBootstrap(int port) throws InterruptedException {\r\n        this.port = port;\r\n        bind();\r\n    }\r\n\r\n    private void bind() throws InterruptedException {\r\n\r\n        EventLoopGroup boss = new NioEventLoopGroup();\r\n        EventLoopGroup worker = new NioEventLoopGroup();\r\n            ServerBootstrap bootstrap = new ServerBootstrap();\r\n            // 通过NoDelay禁用Nagle,使消息立即发出去，不用等待到一定的数据量才发出去\r\n            bootstrap.group(boss, worker).channel(NioServerSocketChannel.class).option(ChannelOption.SO_BACKLOG, 128)\r\n                    .handler(new LoggingHandler(LogLevel.INFO)).option(ChannelOption.TCP_NODELAY, true)\r\n                    .childOption(ChannelOption.SO_KEEPALIVE, true)\r\n                    .childHandler(new ChannelInitializer<SocketChannel>() {\r\n\r\n                        @Override\r\n                        protected void initChannel(SocketChannel ch) throws Exception {\r\n                            ChannelPipeline p = socketChannel.pipeline();\r\n                            p.addLast(new ObjectEncoder());\r\n                            p.addLast(new ObjectDecoder(ClassResolvers.cacheDisabled(null)));\r\n                            p.addLast(new NettyServerHandler());\r\n                        }\r\n\r\n                    });\r\n\r\n            ChannelFuture f = bootstrap.bind(port).sync();\r\n            if (f.isSuccess()) {\r\n                System.out.println(\"server start---------------\");\r\n            }\r\n    }\r\n    \r\n    public static void main(String []args) throws InterruptedException {\r\n        new NettyServerBootstrap(18080);\r\n        while (true){\r\n            SocketChannel channel=(SocketChannel)NettyChannelMap.get(\"001\");\r\n            if(channel!=null){\r\n                AskMsg askMsg=new AskMsg();\r\n                channel.writeAndFlush(askMsg);\r\n            }\r\n            TimeUnit.SECONDS.sleep(5);\r\n        }\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/heartbeat2/NettyServerHandler.java",
    "content": "package com.lyncc.netty.heartbeat2;\r\n\r\nimport io.netty.channel.Channel;\r\nimport io.netty.channel.ChannelHandlerContext;\r\nimport io.netty.channel.SimpleChannelInboundHandler;\r\nimport io.netty.channel.socket.SocketChannel;\r\nimport io.netty.util.ReferenceCountUtil;\r\n\r\npublic class NettyServerHandler extends SimpleChannelInboundHandler<BaseMsg> {\r\n\r\n    @Override\r\n    public void channelInactive(ChannelHandlerContext ctx) throws Exception {\r\n        NettyChannelMap.remove((SocketChannel) ctx.channel());\r\n    }\r\n\r\n    @Override\r\n    protected void channelRead0(ChannelHandlerContext ctx, BaseMsg msg) throws Exception {\r\n        if (MsgType.LOGIN.equals(msg.getType())) {\r\n            LoginMsg loginMsg = (LoginMsg) msg;\r\n            if (\"robin\".equals(loginMsg.getUserName()) && \"yao\".equals(loginMsg.getPassword())) {\r\n                NettyChannelMap.add(loginMsg.getClientId(), (SocketChannel) ctx.channel());\r\n                System.out.println(\"client\" + loginMsg.getClientId() + \" 登录成功\");\r\n            }\r\n        } else {\r\n            if (NettyChannelMap.get(msg.getClientId()) == null) {\r\n                // 说明未登录，或者连接断了，服务器向客户端发起登录请求，让客户端重新登录\r\n                LoginMsg loginMsg = new LoginMsg();\r\n                ctx.channel().writeAndFlush(loginMsg);\r\n            }\r\n        }\r\n        switch (msg.getType()){\r\n        case PING:{\r\n            PingMsg pingMsg=(PingMsg)msg;\r\n            PingMsg replyPing=new PingMsg();\r\n            NettyChannelMap.get(pingMsg.getClientId()).writeAndFlush(replyPing);\r\n        }break;\r\n        case ASK:{\r\n            //收到客户端的请求\r\n            AskMsg askMsg=(AskMsg)msg;\r\n            if(\"authToken\".equals(askMsg.getParams().getAuth())){\r\n                ReplyServerBody replyBody=new ReplyServerBody(\"server info\");\r\n                ReplyMsg replyMsg=new ReplyMsg();\r\n                replyMsg.setBody(replyBody);\r\n                NettyChannelMap.get(askMsg.getClientId()).writeAndFlush(replyMsg);\r\n            }\r\n        }break;\r\n        case REPLY:{\r\n            //收到客户端回复\r\n            ReplyMsg replyMsg=(ReplyMsg)msg;\r\n            ReplyClientBody clientBody=(ReplyClientBody)replyMsg.getBody();\r\n            System.out.println(\"receive client msg: \"+clientBody.getClientInfo());\r\n        }break;\r\n        default:break;\r\n    }\r\n        ReferenceCountUtil.release(msg);\r\n    }\r\n    \r\n    @Override\r\n    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {\r\n        Channel incoming = ctx.channel();\r\n        System.out.println(\"server SimpleChatClient:\"+incoming.remoteAddress()+\"异常\");\r\n        cause.printStackTrace();\r\n        ctx.close();\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/heartbeat2/PingMsg.java",
    "content": "package com.lyncc.netty.heartbeat2;\r\n\r\npublic class PingMsg extends BaseMsg{\r\n    \r\n    public PingMsg() {\r\n        super();\r\n        setType(MsgType.PING);\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/heartbeat2/ReplyBody.java",
    "content": "package com.lyncc.netty.heartbeat2;\r\n\r\nimport java.io.Serializable;\r\n\r\npublic class ReplyBody implements Serializable{\r\n\r\n    /**\r\n     * \r\n     */\r\n    private static final long serialVersionUID = 1L;\r\n    \r\n\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/heartbeat2/ReplyClientBody.java",
    "content": "package com.lyncc.netty.heartbeat2;\r\n\r\npublic class ReplyClientBody extends ReplyBody {\r\n    \r\n    private String clientInfo;\r\n\r\n    public ReplyClientBody(String clientInfo) {\r\n        this.clientInfo = clientInfo;\r\n    }\r\n\r\n    public String getClientInfo() {\r\n        return clientInfo;\r\n    }\r\n\r\n    public void setClientInfo(String clientInfo) {\r\n        this.clientInfo = clientInfo;\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/heartbeat2/ReplyMsg.java",
    "content": "package com.lyncc.netty.heartbeat2;\r\n\r\npublic class ReplyMsg extends BaseMsg {\r\n    \r\n    public ReplyMsg() {\r\n        super();\r\n        setType(MsgType.REPLY);\r\n    }\r\n    \r\n    private ReplyBody body;\r\n\r\n    public ReplyBody getBody() {\r\n        return body;\r\n    }\r\n\r\n    public void setBody(ReplyBody body) {\r\n        this.body = body;\r\n    }\r\n    \r\n    \r\n\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/heartbeat2/ReplyServerBody.java",
    "content": "package com.lyncc.netty.heartbeat2;\r\n\r\npublic class ReplyServerBody extends ReplyBody {\r\n    \r\n    private String serverInfo;\r\n    \r\n    public ReplyServerBody(String serverInfo) {\r\n        this.serverInfo = serverInfo;\r\n    }\r\n    public String getServerInfo() {\r\n        return serverInfo;\r\n    }\r\n    public void setServerInfo(String serverInfo) {\r\n        this.serverInfo = serverInfo;\r\n    }\r\n}"
  },
  {
    "path": "src/main/java/com/lyncc/netty/heartbeats/HeartBeatClientHandler.java",
    "content": "package com.lyncc.netty.heartbeats;\r\n\r\nimport java.util.Date;\r\n\r\nimport io.netty.buffer.ByteBuf;\r\nimport io.netty.buffer.Unpooled;\r\nimport io.netty.channel.ChannelHandlerContext;\r\nimport io.netty.channel.ChannelInboundHandlerAdapter;\r\nimport io.netty.handler.timeout.IdleState;\r\nimport io.netty.handler.timeout.IdleStateEvent;\r\nimport io.netty.util.CharsetUtil;\r\nimport io.netty.util.ReferenceCountUtil;\r\n\r\npublic class HeartBeatClientHandler extends ChannelInboundHandlerAdapter {\r\n\r\n    \r\n    private static final ByteBuf HEARTBEAT_SEQUENCE = Unpooled.unreleasableBuffer(Unpooled.copiedBuffer(\"Heartbeat\",\r\n            CharsetUtil.UTF_8));\r\n    \r\n    private static final int TRY_TIMES = 3;\r\n    \r\n    private int currentTime = 0;\r\n    \r\n    @Override\r\n    public void channelActive(ChannelHandlerContext ctx) throws Exception {\r\n        System.out.println(\"激活时间是：\"+new Date());\r\n        System.out.println(\"HeartBeatClientHandler channelActive\");\r\n        ctx.fireChannelActive();\r\n    }\r\n\r\n    @Override\r\n    public void channelInactive(ChannelHandlerContext ctx) throws Exception {\r\n        System.out.println(\"停止时间是：\"+new Date());\r\n        System.out.println(\"HeartBeatClientHandler channelInactive\");\r\n    }\r\n\r\n    @Override\r\n    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {\r\n        System.out.println(\"循环触发时间：\"+new Date());\r\n        if (evt instanceof IdleStateEvent) {\r\n            IdleStateEvent event = (IdleStateEvent) evt;\r\n            if (event.state() == IdleState.WRITER_IDLE) {\r\n                if(currentTime <= TRY_TIMES){\r\n                    System.out.println(\"currentTime:\"+currentTime);\r\n                    currentTime++;\r\n                    ctx.channel().writeAndFlush(HEARTBEAT_SEQUENCE.duplicate());\r\n                }\r\n            }\r\n        }\r\n    }\r\n\r\n    @Override\r\n    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {\r\n        String message = (String) msg;\r\n        System.out.println(message);\r\n        if (message.equals(\"Heartbeat\")) {\r\n            ctx.write(\"has read message from server\");\r\n            ctx.flush();\r\n        }\r\n        ReferenceCountUtil.release(msg);\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/heartbeats/HeartBeatServer.java",
    "content": "package com.lyncc.netty.heartbeats;\r\n\r\nimport io.netty.bootstrap.ServerBootstrap;\r\nimport io.netty.channel.ChannelFuture;\r\nimport io.netty.channel.ChannelInitializer;\r\nimport io.netty.channel.ChannelOption;\r\nimport io.netty.channel.EventLoopGroup;\r\nimport io.netty.channel.nio.NioEventLoopGroup;\r\nimport io.netty.channel.socket.SocketChannel;\r\nimport io.netty.channel.socket.nio.NioServerSocketChannel;\r\nimport io.netty.handler.codec.string.StringDecoder;\r\nimport io.netty.handler.codec.string.StringEncoder;\r\nimport io.netty.handler.logging.LogLevel;\r\nimport io.netty.handler.logging.LoggingHandler;\r\nimport io.netty.handler.timeout.IdleStateHandler;\r\n\r\nimport java.net.InetSocketAddress;\r\nimport java.util.concurrent.TimeUnit;\r\n\r\npublic class HeartBeatServer {\r\n    \r\nprivate int port;\r\n    \r\n    public HeartBeatServer(int port) {\r\n        this.port = port;\r\n    }\r\n    \r\n    public void start(){\r\n        EventLoopGroup bossGroup = new NioEventLoopGroup(1);\r\n        EventLoopGroup workerGroup = new NioEventLoopGroup();\r\n        try {\r\n            ServerBootstrap sbs = new ServerBootstrap().group(bossGroup,workerGroup).channel(NioServerSocketChannel.class).handler(new LoggingHandler(LogLevel.INFO)).localAddress(new InetSocketAddress(port))\r\n                    .childHandler(new ChannelInitializer<SocketChannel>() {\r\n                        protected void initChannel(SocketChannel ch) throws Exception {\r\n                            ch.pipeline().addLast(new IdleStateHandler(5, 0, 0, TimeUnit.SECONDS));\r\n                            ch.pipeline().addLast(\"decoder\", new StringDecoder());\r\n                            ch.pipeline().addLast(\"encoder\", new StringEncoder());\r\n                            ch.pipeline().addLast(new HeartBeatServerHandler());\r\n                        };\r\n                        \r\n                    }).option(ChannelOption.SO_BACKLOG, 128)   \r\n                    .childOption(ChannelOption.SO_KEEPALIVE, true);\r\n             // 绑定端口，开始接收进来的连接\r\n             ChannelFuture future = sbs.bind(port).sync();  \r\n             \r\n             System.out.println(\"Server start listen at \" + port );\r\n             future.channel().closeFuture().sync();\r\n        } catch (Exception e) {\r\n            bossGroup.shutdownGracefully();\r\n            workerGroup.shutdownGracefully();\r\n        }\r\n    }\r\n    \r\n    public static void main(String[] args) throws Exception {\r\n        int port;\r\n        if (args.length > 0) {\r\n            port = Integer.parseInt(args[0]);\r\n        } else {\r\n            port = 8080;\r\n        }\r\n        new HeartBeatServer(port).start();\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/heartbeats/HeartBeatServerHandler.java",
    "content": "package com.lyncc.netty.heartbeats;\r\n\r\nimport io.netty.channel.ChannelHandlerContext;\r\nimport io.netty.channel.ChannelInboundHandlerAdapter;\r\nimport io.netty.handler.timeout.IdleState;\r\nimport io.netty.handler.timeout.IdleStateEvent;\r\n\r\npublic class HeartBeatServerHandler extends ChannelInboundHandlerAdapter {\r\n\r\n    private int loss_connect_time = 0;\r\n\r\n    @Override\r\n    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {\r\n        if (evt instanceof IdleStateEvent) {\r\n            IdleStateEvent event = (IdleStateEvent) evt;\r\n            if (event.state() == IdleState.READER_IDLE) {\r\n                loss_connect_time++;\r\n                System.out.println(\"5 秒没有接收到客户端的信息了\");\r\n                if (loss_connect_time > 2) {\r\n                    System.out.println(\"关闭这个不活跃的channel\");\r\n                    ctx.channel().close();\r\n                }\r\n            }\r\n        } else {\r\n            super.userEventTriggered(ctx, evt);\r\n        }\r\n    }\r\n\r\n    @Override\r\n    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {\r\n        System.out.println(\"server channelRead..\");\r\n        System.out.println(ctx.channel().remoteAddress() + \"->Server :\" + msg.toString());\r\n    }\r\n\r\n    @Override\r\n    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {\r\n        cause.printStackTrace();\r\n        ctx.close();\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/heartbeats/HeartBeatsClient.java",
    "content": "package com.lyncc.netty.heartbeats;\r\n\r\nimport io.netty.bootstrap.Bootstrap;\r\nimport io.netty.channel.ChannelFuture;\r\nimport io.netty.channel.ChannelInitializer;\r\nimport io.netty.channel.ChannelOption;\r\nimport io.netty.channel.ChannelPipeline;\r\nimport io.netty.channel.EventLoopGroup;\r\nimport io.netty.channel.nio.NioEventLoopGroup;\r\nimport io.netty.channel.socket.SocketChannel;\r\nimport io.netty.channel.socket.nio.NioSocketChannel;\r\nimport io.netty.handler.codec.string.StringDecoder;\r\nimport io.netty.handler.codec.string.StringEncoder;\r\nimport io.netty.handler.logging.LogLevel;\r\nimport io.netty.handler.logging.LoggingHandler;\r\nimport io.netty.handler.timeout.IdleStateHandler;\r\n\r\nimport java.util.concurrent.TimeUnit;\r\n\r\npublic class HeartBeatsClient {\r\n\r\n    public void connect(int port, String host) throws Exception {\r\n        \r\n        \r\n     // Configure the client.\r\n        EventLoopGroup group = new NioEventLoopGroup();\r\n        ChannelFuture future = null;\r\n        try {\r\n            Bootstrap b = new Bootstrap();\r\n            b.group(group)\r\n             .channel(NioSocketChannel.class)\r\n             .option(ChannelOption.TCP_NODELAY, true)\r\n             .handler(new LoggingHandler(LogLevel.INFO))\r\n             .handler(new ChannelInitializer<SocketChannel>() {\r\n                 @Override\r\n                 public void initChannel(SocketChannel ch) throws Exception {\r\n                     ChannelPipeline p = ch.pipeline();\r\n                     p.addLast(\"ping\", new IdleStateHandler(0, 4, 0, TimeUnit.SECONDS));\r\n                     p.addLast(\"decoder\", new StringDecoder());\r\n                     p.addLast(\"encoder\", new StringEncoder());\r\n                     p.addLast(new HeartBeatClientHandler());\r\n                 }\r\n             });\r\n\r\n            future = b.connect(host, port).sync();\r\n            future.channel().closeFuture().sync();\r\n        } finally {\r\n//          group.shutdownGracefully();\r\n          if (null != future) {\r\n              if (future.channel() != null && future.channel().isOpen()) {\r\n                  future.channel().close();\r\n              }\r\n          }\r\n          System.out.println(\"准备重连\");\r\n          connect(port, host);\r\n          System.out.println(\"重连成功\");\r\n        }\r\n    }\r\n\r\n    /**\r\n     * @param args\r\n     * @throws Exception\r\n     */\r\n    public static void main(String[] args) throws Exception {\r\n        int port = 8080;\r\n        if (args != null && args.length > 0) {\r\n            try {\r\n                port = Integer.valueOf(args[0]);\r\n            } catch (NumberFormatException e) {\r\n                // 采用默认值\r\n            }\r\n        }\r\n        new HeartBeatsClient().connect(port, \"127.0.0.1\");\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/hello/HelloWorldClient.java",
    "content": "package com.lyncc.netty.hello;\r\n\r\nimport io.netty.bootstrap.Bootstrap;\r\nimport io.netty.channel.ChannelFuture;\r\nimport io.netty.channel.ChannelInitializer;\r\nimport io.netty.channel.ChannelOption;\r\nimport io.netty.channel.ChannelPipeline;\r\nimport io.netty.channel.EventLoopGroup;\r\nimport io.netty.channel.nio.NioEventLoopGroup;\r\nimport io.netty.channel.socket.SocketChannel;\r\nimport io.netty.channel.socket.nio.NioSocketChannel;\r\nimport io.netty.handler.codec.string.StringDecoder;\r\nimport io.netty.handler.codec.string.StringEncoder;\r\n\r\nimport java.net.InetSocketAddress;\r\nimport java.net.SocketAddress;\r\n\r\npublic class HelloWorldClient {\r\n    \r\n    static final String HOST = System.getProperty(\"host\", \"127.0.0.1\");\r\n    static final int PORT = Integer.parseInt(System.getProperty(\"port\", \"8080\"));\r\n    static final int SIZE = Integer.parseInt(System.getProperty(\"size\", \"256\"));\r\n\r\n    public static void main(String[] args) throws Exception {\r\n        initChannel();\r\n    }\r\n    \r\n    public static void initChannel() throws InterruptedException{\r\n        // Configure the client.\r\n        EventLoopGroup group = new NioEventLoopGroup();\r\n        try {\r\n            Bootstrap b = new Bootstrap();\r\n            b.group(group)\r\n             .channel(NioSocketChannel.class)\r\n             .option(ChannelOption.TCP_NODELAY, true)\r\n             .handler(new ChannelInitializer<SocketChannel>() {\r\n                 @Override\r\n                 public void initChannel(SocketChannel ch) throws Exception {\r\n                     ChannelPipeline p = ch.pipeline();\r\n                     p.addLast(\"decoder\", new StringDecoder());\r\n                     p.addLast(\"encoder\", new StringEncoder());\r\n                     p.addLast(new HelloWorldClientHandler());\r\n                 }\r\n             });\r\n//            SocketAddress socketAddress = InetSocketAddress.createUnresolved(address.getHost(), address.getPort());\r\n            SocketAddress socketAddress =  new InetSocketAddress(HOST, PORT);\r\n            ChannelFuture future = b.connect(socketAddress).sync();\r\n            future.channel().writeAndFlush(\"hello world\");\r\n            future.channel().closeFuture().sync();\r\n        } finally {\r\n            group.shutdownGracefully();\r\n        }\r\n    \r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/hello/HelloWorldClientHandler.java",
    "content": "package com.lyncc.netty.hello;\r\n\r\nimport io.netty.channel.ChannelHandlerContext;\r\nimport io.netty.channel.ChannelInboundHandlerAdapter;\r\n\r\npublic class HelloWorldClientHandler extends ChannelInboundHandlerAdapter{\r\n    \r\n    \r\n      @Override\r\n      public void channelActive(ChannelHandlerContext ctx) {\r\n          System.out.println(\"HelloWorldClientHandler Active\");\r\n          ctx.fireChannelActive();\r\n      }\r\n  \r\n      @Override\r\n      public void channelRead(ChannelHandlerContext ctx, Object msg) {\r\n         System.out.println(\"HelloWorldClientHandler read Message:\"+msg);\r\n      }\r\n      \r\n      @Override\r\n    public void channelInactive(ChannelHandlerContext ctx) throws Exception {\r\n          System.out.println(\"HelloWorldClientHandler inActive===========\");\r\n        super.channelInactive(ctx);\r\n    }\r\n  \r\n  \r\n     @Override\r\n     public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {\r\n         cause.printStackTrace();\r\n         ctx.close();\r\n      }\r\n\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/hello/HelloWorldServer.java",
    "content": "package com.lyncc.netty.hello;\r\n\r\nimport io.netty.bootstrap.ServerBootstrap;\r\nimport io.netty.channel.ChannelFuture;\r\nimport io.netty.channel.ChannelInitializer;\r\nimport io.netty.channel.ChannelOption;\r\nimport io.netty.channel.EventLoopGroup;\r\nimport io.netty.channel.nio.NioEventLoopGroup;\r\nimport io.netty.channel.socket.SocketChannel;\r\nimport io.netty.channel.socket.nio.NioServerSocketChannel;\r\nimport io.netty.handler.codec.string.StringDecoder;\r\nimport io.netty.handler.codec.string.StringEncoder;\r\n\r\nimport java.net.InetSocketAddress;\r\n\r\npublic class HelloWorldServer {\r\n\r\n    private int port;\r\n    \r\n    public HelloWorldServer(int port) {\r\n        this.port = port;\r\n    }\r\n    \r\n    public void start(){\r\n        EventLoopGroup bossGroup = new NioEventLoopGroup(1);\r\n        EventLoopGroup workerGroup = new NioEventLoopGroup();\r\n        try {\r\n            ServerBootstrap sbs = new ServerBootstrap();\r\n            sbs.group(bossGroup,workerGroup);\r\n            sbs.channel(NioServerSocketChannel.class);\r\n            sbs.childHandler(new ChannelInitializer<SocketChannel>() {\r\n                        \r\n                        protected void initChannel(SocketChannel ch) throws Exception {\r\n                            ch.pipeline().addLast(\"decoder\", new StringDecoder());\r\n                            ch.pipeline().addLast(\"encoder\", new StringEncoder());\r\n                            ch.pipeline().addLast(new HelloWorldServerHandler());\r\n                        };\r\n                        \r\n                    }).option(ChannelOption.SO_BACKLOG, 128)   \r\n                    .childOption(ChannelOption.SO_KEEPALIVE, true);\r\n             // 绑定端口，开始接收进来的连接\r\n             ChannelFuture future = sbs.bind(port).sync();  \r\n             \r\n             System.out.println(\"Server start listen at \" + port );\r\n             future.channel().closeFuture().sync();\r\n        } catch (Exception e) {\r\n            bossGroup.shutdownGracefully();\r\n            workerGroup.shutdownGracefully();\r\n        }\r\n    }\r\n    \r\n    public static void main(String[] args) throws Exception {\r\n        int port;\r\n        if (args.length > 0) {\r\n            port = Integer.parseInt(args[0]);\r\n        } else {\r\n            port = 8080;\r\n        }\r\n        new HelloWorldServer(port).start();\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/hello/HelloWorldServerHandler.java",
    "content": "package com.lyncc.netty.hello;\r\n\r\nimport io.netty.channel.ChannelHandlerContext;\r\nimport io.netty.channel.ChannelInboundHandlerAdapter;\r\n\r\npublic class HelloWorldServerHandler extends ChannelInboundHandlerAdapter{\r\n    \r\n\t\r\n\t@Override\r\n\tpublic void channelActive(ChannelHandlerContext ctx) throws Exception {\r\n\t\tSystem.out.println(\"123123\");\r\n\t\tsuper.channelActive(ctx);\r\n\t}\r\n    \r\n    @Override\r\n    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {\r\n        System.out.println(\"server channelRead..\");\r\n        System.out.println(ctx.channel().remoteAddress()+\"->Server :\"+ msg.toString());\r\n        ctx.flush();\r\n    }\r\n    \r\n    @Override\r\n    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {\r\n        cause.printStackTrace();\r\n        ctx.close();\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/idle/AcceptorIdleStateTrigger.java",
    "content": "package com.lyncc.netty.idle;\n\nimport io.netty.channel.ChannelHandler;\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.channel.ChannelInboundHandlerAdapter;\nimport io.netty.handler.timeout.IdleState;\nimport io.netty.handler.timeout.IdleStateEvent;\n\n\n@ChannelHandler.Sharable\npublic class AcceptorIdleStateTrigger extends ChannelInboundHandlerAdapter {\n\n    @Override\n    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {\n        if (evt instanceof IdleStateEvent) {\n            IdleState state = ((IdleStateEvent) evt).state();\n            if (state == IdleState.READER_IDLE) {\n                throw new Exception(\"idle exception\");\n            }\n        } else {\n            super.userEventTriggered(ctx, evt);\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/idle/ChannelHandlerHolder.java",
    "content": "package com.lyncc.netty.idle;\n\nimport io.netty.channel.ChannelHandler;\n\n/**\n * \n * 客户端的ChannelHandler集合，由子类实现，这样做的好处：\n * 继承这个接口的所有子类可以很方便地获取ChannelPipeline中的Handlers\n * 获取到handlers之后方便ChannelPipeline中的handler的初始化和在重连的时候也能很方便\n * 地获取所有的handlers\n */\npublic interface ChannelHandlerHolder {\n\n    ChannelHandler[] handlers();\n}\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/idle/ConnectionWatchdog.java",
    "content": "package com.lyncc.netty.idle;\n\nimport io.netty.bootstrap.Bootstrap;\nimport io.netty.channel.Channel;\nimport io.netty.channel.ChannelFuture;\nimport io.netty.channel.ChannelFutureListener;\nimport io.netty.channel.ChannelHandler.Sharable;\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.channel.ChannelInboundHandlerAdapter;\nimport io.netty.channel.ChannelInitializer;\nimport io.netty.util.Timeout;\nimport io.netty.util.Timer;\nimport io.netty.util.TimerTask;\n\nimport java.util.concurrent.TimeUnit;\n\n/**\n * \n * 重连检测狗，当发现当前的链路不稳定关闭之后，进行12次重连\n */\n@Sharable\npublic abstract class ConnectionWatchdog extends ChannelInboundHandlerAdapter implements TimerTask ,ChannelHandlerHolder{\n    \n    \n    \n    private final Bootstrap bootstrap;\n    private final Timer timer;\n    private final int port;\n    \n    private final String host;\n\n    private volatile boolean reconnect = true;\n    private int attempts;\n    \n    \n    public ConnectionWatchdog(Bootstrap bootstrap, Timer timer, int port,String host, boolean reconnect) {\n        this.bootstrap = bootstrap;\n        this.timer = timer;\n        this.port = port;\n        this.host = host;\n        this.reconnect = reconnect;\n    }\n    \n    /**\n     * channel链路每次active的时候，将其连接的次数重新☞ 0\n     */\n    @Override\n    public void channelActive(ChannelHandlerContext ctx) throws Exception {\n        \n        System.out.println(\"当前链路已经激活了，重连尝试次数重新置为0\");\n        \n        attempts = 0;\n        ctx.fireChannelActive();\n    }\n    \n    @Override\n    public void channelInactive(ChannelHandlerContext ctx) throws Exception {\n        System.out.println(\"链接关闭\");\n        if(reconnect){\n            System.out.println(\"链接关闭，将进行重连\");\n            if (attempts < 12) {\n                attempts++;\n                //重连的间隔时间会越来越长\n                int timeout = 2 << attempts;\n                timer.newTimeout(this, timeout, TimeUnit.MILLISECONDS);\n            }\n        }\n        ctx.fireChannelInactive();\n    }\n    \n\n    public void run(Timeout timeout) throws Exception {\n        \n        ChannelFuture future;\n        //bootstrap已经初始化好了，只需要将handler填入就可以了\n        synchronized (bootstrap) {\n            bootstrap.handler(new ChannelInitializer<Channel>() {\n\n                @Override\n                protected void initChannel(Channel ch) throws Exception {\n                    \n                    ch.pipeline().addLast(handlers());\n                }\n            });\n            future = bootstrap.connect(host,port);\n        }\n        //future对象\n        future.addListener(new ChannelFutureListener() {\n\n            public void operationComplete(ChannelFuture f) throws Exception {\n                boolean succeed = f.isSuccess();\n\n                //如果重连失败，则调用ChannelInactive方法，再次出发重连事件，一直尝试12次，如果失败则不再重连\n                if (!succeed) {\n                    System.out.println(\"重连失败\");\n                    f.channel().pipeline().fireChannelInactive();\n                }else{\n                    System.out.println(\"重连成功\");\n                }\n            }\n        });\n        \n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/idle/ConnectorIdleStateTrigger.java",
    "content": "package com.lyncc.netty.idle;\n\nimport io.netty.buffer.ByteBuf;\nimport io.netty.buffer.Unpooled;\nimport io.netty.channel.ChannelHandler.Sharable;\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.channel.ChannelInboundHandlerAdapter;\nimport io.netty.handler.timeout.IdleState;\nimport io.netty.handler.timeout.IdleStateEvent;\nimport io.netty.util.CharsetUtil;\n\n@Sharable\npublic class ConnectorIdleStateTrigger extends ChannelInboundHandlerAdapter {\n    \n    private static final ByteBuf HEARTBEAT_SEQUENCE = Unpooled.unreleasableBuffer(Unpooled.copiedBuffer(\"Heartbeat\",\n            CharsetUtil.UTF_8));\n\n    @Override\n    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {\n        if (evt instanceof IdleStateEvent) {\n            IdleState state = ((IdleStateEvent) evt).state();\n            if (state == IdleState.WRITER_IDLE) {\n                // write heartbeat to server\n                ctx.writeAndFlush(HEARTBEAT_SEQUENCE.duplicate());\n            }\n        } else {\n            super.userEventTriggered(ctx, evt);\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/idle/HeartBeatClientHandler.java",
    "content": "package com.lyncc.netty.idle;\n\nimport io.netty.channel.ChannelHandler.Sharable;\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.channel.ChannelInboundHandlerAdapter;\nimport io.netty.util.ReferenceCountUtil;\n\nimport java.util.Date;\n\n@Sharable\npublic class HeartBeatClientHandler extends ChannelInboundHandlerAdapter {\n\n    \n    @Override\n    public void channelActive(ChannelHandlerContext ctx) throws Exception {\n        System.out.println(\"激活时间是：\"+new Date());\n        System.out.println(\"HeartBeatClientHandler channelActive\");\n        ctx.fireChannelActive();\n    }\n\n    @Override\n    public void channelInactive(ChannelHandlerContext ctx) throws Exception {\n        System.out.println(\"停止时间是：\"+new Date());\n        System.out.println(\"HeartBeatClientHandler channelInactive\");\n    }\n\n\n    @Override\n    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {\n        String message = (String) msg;\n        System.out.println(message);\n        if (message.equals(\"Heartbeat\")) {\n            ctx.write(\"has read message from server\");\n            ctx.flush();\n        }\n        ReferenceCountUtil.release(msg);\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/idle/HeartBeatServer.java",
    "content": "package com.lyncc.netty.idle;\n\nimport io.netty.bootstrap.ServerBootstrap;\nimport io.netty.channel.ChannelFuture;\nimport io.netty.channel.ChannelInitializer;\nimport io.netty.channel.ChannelOption;\nimport io.netty.channel.EventLoopGroup;\nimport io.netty.channel.nio.NioEventLoopGroup;\nimport io.netty.channel.socket.SocketChannel;\nimport io.netty.channel.socket.nio.NioServerSocketChannel;\nimport io.netty.handler.codec.string.StringDecoder;\nimport io.netty.handler.codec.string.StringEncoder;\nimport io.netty.handler.logging.LogLevel;\nimport io.netty.handler.logging.LoggingHandler;\nimport io.netty.handler.timeout.IdleStateHandler;\n\nimport java.net.InetSocketAddress;\nimport java.util.concurrent.TimeUnit;\n\npublic class HeartBeatServer {\n    \n    private final AcceptorIdleStateTrigger idleStateTrigger = new AcceptorIdleStateTrigger();\n    \n    private int port;\n\n    public HeartBeatServer(int port) {\n        this.port = port;\n    }\n\n    public void start() {\n        EventLoopGroup bossGroup = new NioEventLoopGroup(1);\n        EventLoopGroup workerGroup = new NioEventLoopGroup();\n        try {\n            ServerBootstrap sbs = new ServerBootstrap().group(bossGroup, workerGroup)\n                    .channel(NioServerSocketChannel.class).handler(new LoggingHandler(LogLevel.INFO))\n                    .localAddress(new InetSocketAddress(port)).childHandler(new ChannelInitializer<SocketChannel>() {\n                        protected void initChannel(SocketChannel ch) throws Exception {\n                            ch.pipeline().addLast(new IdleStateHandler(5, 0, 0, TimeUnit.SECONDS));\n                            ch.pipeline().addLast(idleStateTrigger);\n                            ch.pipeline().addLast(\"decoder\", new StringDecoder());\n                            ch.pipeline().addLast(\"encoder\", new StringEncoder());\n                            ch.pipeline().addLast(new HeartBeatServerHandler());\n                        };\n\n                    }).option(ChannelOption.SO_BACKLOG, 128).childOption(ChannelOption.SO_KEEPALIVE, true);\n            // 绑定端口，开始接收进来的连接\n            ChannelFuture future = sbs.bind(port).sync();\n\n            System.out.println(\"Server start listen at \" + port);\n            future.channel().closeFuture().sync();\n        } catch (Exception e) {\n            bossGroup.shutdownGracefully();\n            workerGroup.shutdownGracefully();\n        }\n    }\n\n    public static void main(String[] args) throws Exception {\n        int port;\n        if (args.length > 0) {\n            port = Integer.parseInt(args[0]);\n        } else {\n            port = 8080;\n        }\n        new HeartBeatServer(port).start();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/idle/HeartBeatServerHandler.java",
    "content": "package com.lyncc.netty.idle;\n\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.channel.ChannelInboundHandlerAdapter;\n\npublic class HeartBeatServerHandler extends ChannelInboundHandlerAdapter {\n\n\n    @Override\n    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {\n        System.out.println(\"server channelRead..\");\n        System.out.println(ctx.channel().remoteAddress() + \"->Server :\" + msg.toString());\n    }\n\n    @Override\n    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {\n        cause.printStackTrace();\n        ctx.close();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/idle/HeartBeatsClient.java",
    "content": "package com.lyncc.netty.idle;\n\nimport io.netty.bootstrap.Bootstrap;\nimport io.netty.channel.Channel;\nimport io.netty.channel.ChannelFuture;\nimport io.netty.channel.ChannelHandler;\nimport io.netty.channel.ChannelInitializer;\nimport io.netty.channel.EventLoopGroup;\nimport io.netty.channel.nio.NioEventLoopGroup;\nimport io.netty.channel.socket.nio.NioSocketChannel;\nimport io.netty.handler.codec.string.StringDecoder;\nimport io.netty.handler.codec.string.StringEncoder;\nimport io.netty.handler.logging.LogLevel;\nimport io.netty.handler.logging.LoggingHandler;\nimport io.netty.handler.timeout.IdleStateHandler;\nimport io.netty.util.HashedWheelTimer;\n\nimport java.util.concurrent.TimeUnit;\n\npublic class HeartBeatsClient {\n    \n    protected final HashedWheelTimer timer = new HashedWheelTimer();\n    \n    private Bootstrap boot;\n    \n    private final ConnectorIdleStateTrigger idleStateTrigger = new ConnectorIdleStateTrigger();\n\n    public void connect(int port, String host) throws Exception {\n        \n        EventLoopGroup group = new NioEventLoopGroup();  \n        \n        boot = new Bootstrap();\n        boot.group(group).channel(NioSocketChannel.class).handler(new LoggingHandler(LogLevel.INFO));\n            \n        final ConnectionWatchdog watchdog = new ConnectionWatchdog(boot, timer, port,host, true) {\n\n                public ChannelHandler[] handlers() {\n                    return new ChannelHandler[] {\n                            this,\n                            new IdleStateHandler(0, 4, 0, TimeUnit.SECONDS),\n                            idleStateTrigger,\n                            new StringDecoder(),\n                            new StringEncoder(),\n                            new HeartBeatClientHandler()\n                    };\n                }\n            };\n            \n            ChannelFuture future;\n            //进行连接\n            try {\n                synchronized (boot) {\n                    boot.handler(new ChannelInitializer<Channel>() {\n\n                        //初始化channel\n                        @Override\n                        protected void initChannel(Channel ch) throws Exception {\n                            ch.pipeline().addLast(watchdog.handlers());\n                        }\n                    });\n\n                    future = boot.connect(host,port);\n                }\n\n                // 以下代码在synchronized同步块外面是安全的\n                future.sync();\n            } catch (Throwable t) {\n                throw new Exception(\"connects to  fails\", t);\n            }\n    }\n\n    /**\n     * @param args\n     * @throws Exception\n     */\n    public static void main(String[] args) throws Exception {\n        int port = 8080;\n        if (args != null && args.length > 0) {\n            try {\n                port = Integer.valueOf(args[0]);\n            } catch (NumberFormatException e) {\n                // 采用默认值\n            }\n        }\n        new HeartBeatsClient().connect(port, \"127.0.0.1\");\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/keepalive/Constants.java",
    "content": "package com.lyncc.netty.keepalive;\r\n\r\npublic class Constants {\r\n\r\n\tpublic static final int REQ_CODE = 1 ;\r\n\t\r\n\tpublic static final int RET_CODE = 2 ;\r\n\t\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/keepalive/Heartbeat.java",
    "content": "package com.lyncc.netty.keepalive;\r\n\r\nimport io.netty.channel.ChannelHandlerContext;\r\nimport io.netty.channel.SimpleChannelInboundHandler;\r\nimport io.netty.handler.timeout.IdleState;\r\nimport io.netty.handler.timeout.IdleStateEvent;\r\n\r\npublic class Heartbeat extends SimpleChannelInboundHandler<KeepAliveMessage>{\r\n    \r\n    //失败计数器：未收到client端发送的ping请求\r\n    private int unRecPingTimes = 0 ;\r\n    \r\n    //每个chanel对应一个线程，此处用来存储对应于每个线程的一些基础数据，此处不一定要为KeepAliveMessage对象\r\n    ThreadLocal<KeepAliveMessage> localMsgInfo = new ThreadLocal<KeepAliveMessage>(); \r\n    \r\n    // 定义客户端没有收到服务端的pong消息的最大次数\r\n    private static final int MAX_UN_REC_PING_TIMES = 3;\r\n\r\n    @Override\r\n    protected void channelRead0(ChannelHandlerContext ctx, KeepAliveMessage msg) throws Exception {\r\n        \r\n        System.out.println(ctx.channel().remoteAddress() + \" Say : sn=\" + msg.getSn()+\",reqcode=\"+msg.getReqCode());\r\n        \r\n        if(Utils.notEmpty(msg.getSn())&&msg.getReqCode()==1){\r\n            msg.setReqCode(Constants.RET_CODE);\r\n            ctx.channel().writeAndFlush(msg);\r\n            // 失败计数器清零\r\n            unRecPingTimes = 0;\r\n            if(localMsgInfo.get()==null){\r\n                KeepAliveMessage localMsg = new KeepAliveMessage();\r\n                localMsg.setSn(msg.getSn());\r\n                localMsgInfo.set(localMsg);\r\n            }\r\n        }else{\r\n            ctx.channel().close();\r\n        }\r\n        \r\n    }\r\n    \r\n    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {\r\n        if (evt instanceof IdleStateEvent) {\r\n            IdleStateEvent event = (IdleStateEvent) evt;\r\n            if (event.state() == IdleState.READER_IDLE) {\r\n                /*读超时*/\r\n                System.out.println(\"===服务端===(READER_IDLE 读超时)\");\r\n                // 失败计数器次数大于等于3次的时候，关闭链接，等待client重连\r\n                if(unRecPingTimes >= MAX_UN_REC_PING_TIMES){\r\n                    System.out.println(\"===服务端===(读超时，关闭chanel)\");\r\n                    // 连续超过N次未收到client的ping消息，那么关闭该通道，等待client重连\r\n                    ctx.channel().close();\r\n                }else{\r\n                    // 失败计数器加1\r\n                    unRecPingTimes++;\r\n                }\r\n            } else if (event.state() == IdleState.WRITER_IDLE) {\r\n                /*写超时*/   \r\n                System.out.println(\"===服务端===(WRITER_IDLE 写超时)\");\r\n            } else if (event.state() == IdleState.ALL_IDLE) {\r\n                /*总超时*/\r\n                System.out.println(\"===服务端===(ALL_IDLE 总超时)\");\r\n            }\r\n        }\r\n    }\r\n    \r\n    @Override\r\n    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {\r\n        System.out.println(\"错误原因：\"+cause.getMessage());\r\n        if(localMsgInfo.get()!=null){\r\n            /*\r\n             * 从管理集合中移除设备号等唯一标示，标示设备离线\r\n             */\r\n            // TODO\r\n        }\r\n        ctx.channel().close();\r\n    }\r\n\r\n    @Override\r\n    public void channelActive(ChannelHandlerContext ctx) throws Exception {\r\n        System.out.println(\"Client active \");\r\n        super.channelActive(ctx);\r\n    }\r\n    \r\n    @Override\r\n    public void channelInactive(ChannelHandlerContext ctx) throws Exception {\r\n        // 关闭，等待重连\r\n        ctx.close();\r\n        if(localMsgInfo.get()!=null){\r\n            /*\r\n             * 从管理集合中移除设备号等唯一标示，标示设备离线\r\n             */\r\n            // TODO\r\n        }\r\n        System.out.println(\"===服务端===(客户端失效)\");\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/keepalive/KeepAliveClient.java",
    "content": "package com.lyncc.netty.keepalive;\r\n\r\nimport io.netty.bootstrap.Bootstrap;\r\nimport io.netty.channel.Channel;\r\nimport io.netty.channel.ChannelHandlerContext;\r\nimport io.netty.channel.ChannelInitializer;\r\nimport io.netty.channel.ChannelPipeline;\r\nimport io.netty.channel.EventLoopGroup;\r\nimport io.netty.channel.SimpleChannelInboundHandler;\r\nimport io.netty.channel.nio.NioEventLoopGroup;\r\nimport io.netty.channel.socket.SocketChannel;\r\nimport io.netty.channel.socket.nio.NioSocketChannel;\r\nimport io.netty.handler.codec.serialization.ClassResolvers;\r\nimport io.netty.handler.codec.serialization.ObjectDecoder;\r\nimport io.netty.handler.codec.serialization.ObjectEncoder;\r\nimport io.netty.handler.timeout.IdleState;\r\nimport io.netty.handler.timeout.IdleStateEvent;\r\nimport io.netty.handler.timeout.IdleStateHandler;\r\n\r\nimport java.util.concurrent.Executors;\r\nimport java.util.concurrent.ScheduledExecutorService;\r\nimport java.util.concurrent.TimeUnit;\r\n\r\npublic class KeepAliveClient {\r\n\r\n\tprivate String host ;\r\n\tprivate int port ;\r\n\t\r\n\tprivate EventLoopGroup group ;\r\n\t\r\n\tprivate Bootstrap b ;\r\n\t\r\n\tprivate Channel ch ;\r\n\t\r\n\t// 定义客户端没有收到服务端的pong消息的最大次数\r\n\tprivate static final int MAX_UN_REC_PONG_TIMES = 3;\r\n\t\r\n\t// 多长时间未请求后，发送心跳\r\n\tprivate static final int WRITE_WAIT_SECONDS = 5;\r\n\t\r\n\t// 隔N秒后重连\r\n\tprivate static final int RE_CONN_WAIT_SECONDS = 5;\r\n\t\r\n\t// 客户端连续N次没有收到服务端的pong消息  计数器\r\n\tprivate int unRecPongTimes = 0 ;\r\n\t\r\n\tprivate ScheduledExecutorService executorService ;\r\n\t\r\n\t// 是否停止\r\n\tprivate boolean isStop = false ;\r\n\r\n\tpublic KeepAliveClient(String host, int port) {\r\n\t\tthis.host = host ;\r\n\t\tthis.port = port ;\r\n\t\tgroup = new NioEventLoopGroup();\r\n\t\tb = new Bootstrap();\r\n\t\tb.group(group).channel(NioSocketChannel.class).handler(new HeartbeatInitializer());\r\n\t}\r\n\r\n\tpublic void start() {\r\n\t\tconnServer();\r\n\t}\r\n\t\r\n\tprivate void connServer(){\r\n\t\t\r\n\t\tisStop = false;\r\n\t\t\r\n\t\tif(executorService!=null){\r\n\t\t\texecutorService.shutdown();\r\n\t\t}\r\n\t\texecutorService = Executors.newScheduledThreadPool(1);\r\n\t\texecutorService.scheduleWithFixedDelay(new Runnable() {\r\n\t\t\t\r\n\t\t\tboolean isConnSucc = true;\r\n\t\t\t\r\n\t\t\tpublic void run() {\r\n\t\t\t\ttry {\r\n\t\t\t\t\t// 重置计数器\r\n\t\t\t\t\tunRecPongTimes = 0;\r\n\t\t\t\t\t// 连接服务端\r\n\t\t\t\t\tif(ch!=null&&ch.isOpen()){\r\n\t\t\t\t\t\tch.close();\r\n\t\t\t\t\t}\r\n\t\t\t\t\tch = b.connect(host, port).sync().channel();\r\n\t\t\t\t\t// 此方法会阻塞\r\n//\t\t\t\t\tch.closeFuture().sync();\r\n\t\t\t\t\tSystem.out.println(\"connect server finish\");\r\n\t\t\t\t} catch (Exception e) {\r\n\t\t\t\t\te.printStackTrace();\r\n\t\t\t\t\tisConnSucc = false ;\r\n\t\t\t\t} finally{\r\n\t\t\t\t\tif(isConnSucc){\r\n\t\t\t\t\t\tif(executorService!=null){\r\n\t\t\t\t\t\t\texecutorService.shutdown();\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}, RE_CONN_WAIT_SECONDS, RE_CONN_WAIT_SECONDS, TimeUnit.SECONDS);\r\n\t}\r\n\t\r\n\tpublic class HeartbeatInitializer extends ChannelInitializer<SocketChannel> {\r\n\t\t \r\n\t    @Override\r\n\t    protected void initChannel(SocketChannel ch) throws Exception {\r\n\t        ChannelPipeline pipeline = ch.pipeline();\r\n\t \r\n\t\t\tpipeline.addLast(\"decoder\", new ObjectDecoder(ClassResolvers.cacheDisabled(this.getClass().getClassLoader())));\r\n\t        pipeline.addLast(\"encoder\", new ObjectEncoder());\r\n\t \r\n\t        pipeline.addLast(\"ping\", new IdleStateHandler(0, WRITE_WAIT_SECONDS, 0,TimeUnit.SECONDS));\r\n\t        // 客户端的逻辑\r\n\t        pipeline.addLast(\"handler\", new ClientHandler());\r\n\t    }\r\n\t}\r\n\r\n\tpublic class ClientHandler extends SimpleChannelInboundHandler<KeepAliveMessage> {\r\n\t\t \r\n\t    @Override\r\n\t    protected void channelRead0(ChannelHandlerContext ctx, KeepAliveMessage msg)\r\n\t            throws Exception {\r\n\t    \tSystem.out.println(\"Server say : sn=\" + msg.getSn()+\",reqcode=\"+msg.getReqCode());\r\n\t        if (Constants.RET_CODE == msg.getReqCode()) {\r\n\t        \t// 计数器清零\r\n\t        \tunRecPongTimes = 0;\r\n\t        }\r\n\t    }\r\n\t    \r\n\t    @Override\r\n\t    public void channelActive(ChannelHandlerContext ctx) throws Exception {\r\n\t        System.out.println(\"Client active \");\r\n\t        super.channelActive(ctx);\r\n\t    }\r\n\r\n\t    @Override\r\n\t    public void channelInactive(ChannelHandlerContext ctx) throws Exception {\r\n\t        System.out.println(\"Client close \");\r\n\t        super.channelInactive(ctx);\r\n\t        /*\r\n\t         * 重连\r\n\t         */\r\n\t        if(!isStop){\r\n\t        \tconnServer();\r\n\t        }\r\n\t    }\r\n\t    \r\n\t    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {\r\n\t        if (evt instanceof IdleStateEvent) {\r\n\t            IdleStateEvent event = (IdleStateEvent) evt;\r\n\t            if (event.state() == IdleState.READER_IDLE) {\r\n\t                /*读超时*/\r\n\t                System.out.println(\"===服务端===(READER_IDLE 读超时)\");\r\n\t            } else if (event.state() == IdleState.WRITER_IDLE) {\r\n\t                /*写超时*/   \r\n\t                System.out.println(\"===服务端===(WRITER_IDLE 写超时)\");\r\n\t                if(unRecPongTimes < MAX_UN_REC_PONG_TIMES){\r\n\t                \tctx.channel().writeAndFlush(getSrcMsg()) ;\r\n\t                \tunRecPongTimes++;\r\n\t                }else{\r\n\t                \tctx.channel().close();\r\n\t                }\r\n\t            } else if (event.state() == IdleState.ALL_IDLE) {\r\n\t                /*总超时*/\r\n\t                System.out.println(\"===服务端===(ALL_IDLE 总超时)\");\r\n\t            }\r\n\t        }\r\n\t    }\r\n\t}\r\n\t\r\n\tprivate KeepAliveMessage getSrcMsg(){\r\n\t\tKeepAliveMessage keepAliveMessage = new KeepAliveMessage();\r\n\t\t// 设备码\r\n        keepAliveMessage.setSn(\"sn_123456abcdfef\");\r\n        keepAliveMessage.setReqCode(Constants.REQ_CODE);\r\n        return keepAliveMessage ;\r\n\t}\r\n\t\r\n\tpublic void stop(){\r\n\t\tisStop = true;\r\n\t\tif(ch!=null&&ch.isOpen()){\r\n\t\t\tch.close();\r\n\t\t}\r\n\t\tif(executorService!=null){\r\n\t\t\texecutorService.shutdown();\r\n\t\t}\r\n\t}\r\n\t\r\n\t/**\r\n\t * @param args\r\n\t */\r\n\tpublic static void main(String[] args) {\r\n\t\tKeepAliveClient keepAliveServer = new KeepAliveClient(\"127.0.0.1\",1666);\r\n\t\tkeepAliveServer.start();\r\n\t}\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/keepalive/KeepAliveMessage.java",
    "content": "package com.lyncc.netty.keepalive;\r\n\r\npublic class KeepAliveMessage implements java.io.Serializable{\r\n\r\n\tprivate static final long serialVersionUID = 479148324800517968L;\r\n\r\n\tprivate String sn ;\r\n\t\r\n\tprivate int reqCode ; // 1:心跳请求  2:心跳反馈\r\n\r\n\tpublic String getSn() {\r\n\t\treturn sn;\r\n\t}\r\n\r\n\tpublic void setSn(String sn) {\r\n\t\tthis.sn = sn;\r\n\t}\r\n\r\n\tpublic int getReqCode() {\r\n\t\treturn reqCode;\r\n\t}\r\n\r\n\tpublic void setReqCode(int reqCode) {\r\n\t\tthis.reqCode = reqCode;\r\n\t}\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/keepalive/KeepAliveServer.java",
    "content": "package com.lyncc.netty.keepalive;\r\n\r\nimport io.netty.bootstrap.ServerBootstrap;\r\nimport io.netty.channel.ChannelFuture;\r\nimport io.netty.channel.EventLoopGroup;\r\nimport io.netty.channel.nio.NioEventLoopGroup;\r\nimport io.netty.channel.socket.nio.NioServerSocketChannel;\r\n\r\npublic class KeepAliveServer {\r\n    \r\n    private int port ;\r\n\r\n    public KeepAliveServer(int port) {\r\n        this.port = port;\r\n    }\r\n    \r\n    ChannelFuture f ;\r\n    \r\n    ServerBootstrap b ;\r\n    \r\n    public void startServer() {\r\n        EventLoopGroup bossGroup = new NioEventLoopGroup();\r\n        EventLoopGroup workerGroup = new NioEventLoopGroup();\r\n        \r\n        try {\r\n            b = new ServerBootstrap();\r\n            b.group(bossGroup, workerGroup);\r\n            b.channel(NioServerSocketChannel.class);\r\n            b.childHandler(new KeepAliveServerInitializer());\r\n            // 服务器绑定端口监听\r\n            f = b.bind(port).sync();\r\n            // 监听服务器关闭监听，此方法会阻塞\r\n            f.channel().closeFuture().sync();\r\n\r\n        } catch (InterruptedException e) {\r\n            e.printStackTrace();\r\n        } finally {\r\n            bossGroup.shutdownGracefully();\r\n            workerGroup.shutdownGracefully();\r\n        }\r\n        \r\n    }\r\n\r\n}\r\n\r\n\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/keepalive/KeepAliveServerInitializer.java",
    "content": "package com.lyncc.netty.keepalive;\r\n\r\nimport io.netty.channel.ChannelInitializer;\r\nimport io.netty.channel.ChannelPipeline;\r\nimport io.netty.channel.socket.SocketChannel;\r\nimport io.netty.handler.codec.serialization.ClassResolvers;\r\nimport io.netty.handler.codec.serialization.ObjectDecoder;\r\nimport io.netty.handler.codec.serialization.ObjectEncoder;\r\nimport io.netty.handler.timeout.IdleStateHandler;\r\n\r\nimport java.util.concurrent.TimeUnit;\r\n\r\npublic class KeepAliveServerInitializer extends ChannelInitializer<SocketChannel>{\r\n    \r\n    // 设置6秒检测chanel是否接受过心跳数据\r\n    private static final int READ_WAIT_SECONDS = 6;\r\n    \r\n    // 定义客户端没有收到服务端的pong消息的最大次数\r\n    private static final int MAX_UN_REC_PING_TIMES = 3;\r\n    \r\n\r\n    @Override\r\n    protected void initChannel(SocketChannel ch) throws Exception {\r\n        ChannelPipeline pipeline = ch.pipeline();\r\n        pipeline.addLast(\"decoder\", new ObjectDecoder(ClassResolvers.cacheDisabled(this.getClass().getClassLoader())));\r\n        pipeline.addLast(\"encoder\", new ObjectEncoder());\r\n        pipeline.addLast(\"pong\", new IdleStateHandler(READ_WAIT_SECONDS, 0, 0,TimeUnit.SECONDS));\r\n        \r\n        pipeline.addLast(\"handler\", new Heartbeat());\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/keepalive/Utils.java",
    "content": "package com.lyncc.netty.keepalive;\r\n\r\nimport java.util.Collection;\r\n\r\npublic class Utils {\r\n\r\n\t/**\r\n\t * 判断对象是否为空<br />\r\n\t * 不为空返回true，为空返回false\r\n\t * \r\n\t * @param o\r\n\t * @return\r\n\t */\r\n\tpublic static boolean notEmpty(Object o) {\r\n\t\tboolean notEmpty = false;\r\n\t\tif (o instanceof String) {\r\n\t\t\tString s = (String) o;\r\n\t\t\tif (s != null && !\"\".equals(s) && !\"undefined\".equals(s)\r\n\t\t\t\t\t&& !\"null\".equals(s)) {\r\n\t\t\t\tnotEmpty = true;\r\n\t\t\t}\r\n\t\t} else if (o instanceof Collection) {\r\n\t\t\tCollection c = (Collection) o;\r\n\t\t\tif (c != null && c.size() > 0) {\r\n\t\t\t\tnotEmpty = true;\r\n\t\t\t}\r\n\t\t} else if (o instanceof Object[]) {\r\n\t\t\tObject[] arr = (Object[]) o;\r\n\t\t\tif (arr != null && arr.length > 0) {\r\n\t\t\t\tnotEmpty = true;\r\n\t\t\t}\r\n\t\t} else if (o != null) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\treturn notEmpty;\r\n\t}\r\n    \r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/nio/EchoClient.java",
    "content": "package com.lyncc.netty.nio;\n\nimport java.io.IOException;\nimport java.net.InetSocketAddress;\nimport java.nio.ByteBuffer;\nimport java.nio.channels.SelectionKey;\nimport java.nio.channels.Selector;\nimport java.nio.channels.SocketChannel;\nimport java.nio.charset.Charset;\nimport java.util.Set;\n\npublic class EchoClient {\n\n\tpublic static void main(String[] args) throws IOException {\n\n\t\tSocketChannel channel = SocketChannel.open();\n\t\tchannel.configureBlocking(false);\n\t\tInetSocketAddress s = new InetSocketAddress(\"localhost\", 2000);\n\t\tchannel.connect(s);\n\n\t\tSelector selector = Selector.open();\n\t\tchannel.register(selector, SelectionKey.OP_CONNECT | SelectionKey.OP_READ);\n\n\t\tCharset charset = Charset.forName(\"GBK\");\n\n\t\tboolean isFinished = false;\n\t\twhile (!isFinished) {\n\t\t\tint num = selector.select();\n\t\t\tif (num > 0) {\n\t\t\t\tSet<SelectionKey> keys = selector.selectedKeys();\n\t\t\t\tfor (SelectionKey k : keys) {\n\t\t\t\t\tif (k.isConnectable()) {\n\t\t\t\t\t\tSocketChannel sc = (SocketChannel) k.channel();\n\t\t\t\t\t\tsc.configureBlocking(false);\n\t\t\t\t\t\tsc.finishConnect();\n\t\t\t\t\t\tsc.register(selector, SelectionKey.OP_READ);\n\n\t\t\t\t\t\tByteBuffer echoBuffer = ByteBuffer.allocate(1024);\n\t\t\t\t\t\tByteBuffer info = charset.encode(\"好了克隆技术杜洛克防水堵漏开发!\");\n\t\t\t\t\t\techoBuffer.put(info);\n\n\t\t\t\t\t\techoBuffer.flip();\n\n\t\t\t\t\t\tsc.write(echoBuffer);\n\t\t\t\t\t\techoBuffer.clear();\n\n\t\t\t\t\t} else if (k.isValid() && k.isReadable()) {\n\t\t\t\t\t\tByteBuffer echoBuffer = ByteBuffer.allocate(1024);\n\t\t\t\t\t\tSocketChannel sc = (SocketChannel) k.channel();\n\t\t\t\t\t\tsc.read(echoBuffer);\n\t\t\t\t\t\techoBuffer.flip();\n\n\t\t\t\t\t\tSystem.out.println(\"echo server return:\" + charset.decode(echoBuffer).toString());\n\t\t\t\t\t\techoBuffer.clear();\n\n\t\t\t\t\t\tisFinished = true;\n\n\t\t\t\t\t\tk.cancel();\n\t\t\t\t\t\tsc.close();\n\t\t\t\t\t\tselector.close();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/nio/MultiPortEchoServer.java",
    "content": "package com.lyncc.netty.nio;\n\nimport java.io.IOException;\nimport java.net.InetSocketAddress;\nimport java.net.ServerSocket;\nimport java.nio.ByteBuffer;\nimport java.nio.channels.SelectionKey;\nimport java.nio.channels.Selector;\nimport java.nio.channels.ServerSocketChannel;\nimport java.nio.channels.SocketChannel;\nimport java.nio.charset.Charset;\nimport java.util.Iterator;\nimport java.util.Set;\n\npublic class MultiPortEchoServer {\nprivate Charset charset=Charset.forName(\"GBK\");\n    \n    private int[] ports;\n    \n    /**\n     * @param args\n     */\n    public static void main(String[] args) {\n        \n        int[] ps = {2000,2001};   //默认监听2000,2001端口\n        \n        new MultiPortEchoServer(ps);\n\n    }\n    \n    public MultiPortEchoServer(int[] ports){\n        this.ports = ports;\n        try {\n            go();\n        } catch (IOException e) {\n            // TODO Auto-generated catch block\n            e.printStackTrace();\n        }\n    }\n    \n    public void go() throws IOException{\n        \n        Selector selector = Selector.open();\n        \n        for(int i=0;i<ports.length;i++){\n            ServerSocketChannel channel = ServerSocketChannel.open();\n            channel.configureBlocking(false);\n            ServerSocket socket = channel.socket();\n            InetSocketAddress address = new InetSocketAddress(\"localhost\",ports[i]);\n            socket.bind(address);\n            \n            //注册接受连接事件\n            channel.register(selector, SelectionKey.OP_ACCEPT);\n            \n            System.out.println( \"Going to listen on \"+ports[i] ); \n        }\n        \n        while(true){\n            \n            int num = selector.select();\n            Set<SelectionKey> keys = selector.selectedKeys();\n            Iterator<SelectionKey> iter = keys.iterator();\n            while(iter.hasNext()){\n                SelectionKey key = iter.next();\n                if((key.readyOps()&SelectionKey.OP_ACCEPT)==SelectionKey.OP_ACCEPT){\n                    ServerSocketChannel  ssc = (ServerSocketChannel) key.channel();\n                    SocketChannel sc = ssc.accept();\n                    sc.configureBlocking(false);\n                    \n                    sc.register(selector, SelectionKey.OP_READ);\n                    iter.remove();\n                }else if((key.readyOps()&SelectionKey.OP_READ)==SelectionKey.OP_READ){\n                    \n                    SocketChannel sc = (SocketChannel) key.channel();\n                    \n                    if(!sc.isOpen()){\n                        selector = Selector.open();\n                    }else{\n                        ByteBuffer echoBuffer = ByteBuffer.allocate(1024);  \n                        \n                        //int x = sc.read(echoBuffer);\n                        while(sc.read(echoBuffer)>0){\n                            \n                            System.out.println( \"Echoed \"+charset.decode(echoBuffer).toString()+\" from \"+sc.socket().getInetAddress().getHostAddress() );  \n                            echoBuffer.flip();\n                            sc.write(echoBuffer);\n                            echoBuffer.clear();\n                        }\n                        \n                        \n                        iter.remove();\n                        \n                        /*返回信息后关闭连接*/\n                        key.cancel();\n                        sc.close();\n                    }\n                }\n            }\n            \n            keys.clear();\n        }\n    }\n\n\n}\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/nio/package-info.java",
    "content": "/**\n * \n */\n/**\n * @author BazingaLyn\n * @description\n * @time\n * @modifytime\n */\npackage com.lyncc.netty.nio;"
  },
  {
    "path": "src/main/java/com/lyncc/netty/production/ChannelHandlerHolder.java",
    "content": "/*\n * Copyright (c) 2015 The Jupiter Project\n *\n * Licensed under the Apache License, version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.lyncc.netty.production;\n\nimport io.netty.channel.ChannelHandler;\n\n/**\n * jupiter\n * org.jupiter.transport.netty.handler\n *\n * @author jiachun.fjc\n */\npublic interface ChannelHandlerHolder {\n\n    ChannelHandler[] handlers();\n}\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/production/ConnectionWatchdog.java",
    "content": "package com.lyncc.netty.production;\n\nimport static java.util.concurrent.TimeUnit.MILLISECONDS;\nimport io.netty.bootstrap.Bootstrap;\nimport io.netty.channel.Channel;\nimport io.netty.channel.ChannelFuture;\nimport io.netty.channel.ChannelFutureListener;\nimport io.netty.channel.ChannelHandler;\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.channel.ChannelInboundHandlerAdapter;\nimport io.netty.channel.ChannelInitializer;\nimport io.netty.util.Timeout;\nimport io.netty.util.Timer;\nimport io.netty.util.TimerTask;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n@ChannelHandler.Sharable\npublic abstract class ConnectionWatchdog extends ChannelInboundHandlerAdapter implements TimerTask, ChannelHandlerHolder {\n\n\tprivate static final Logger logger = LoggerFactory.getLogger(ConnectionWatchdog.class);\n\n    private final Bootstrap bootstrap;\n    private final Timer timer;\n    private final int port;\n    private final String host;\n\n    private volatile boolean reconnect = true;\n    private int attempts;\n\n    public ConnectionWatchdog(Bootstrap bootstrap, Timer timer, int port,String host) {\n        this.bootstrap = bootstrap;\n        this.timer = timer;\n        this.port = port;\n        this.host = host;\n    }\n\n    public boolean isReconnect() {\n        return reconnect;\n    }\n\n    public void setReconnect(boolean reconnect) {\n        this.reconnect = reconnect;\n    }\n\n    @Override\n    public void channelActive(ChannelHandlerContext ctx) throws Exception {\n        Channel channel = ctx.channel();\n        attempts = 0;\n\n        logger.info(\"Connects with {}.\", channel);\n\n        ctx.fireChannelActive();\n    }\n\n    /**\n     * 因为链路断掉之后，会触发channelInActive方法，进行重连\n     */\n    @Override\n    public void channelInactive(ChannelHandlerContext ctx) throws Exception {\n        boolean doReconnect = reconnect;\n        if (doReconnect) {\n            if (attempts < 12) {\n                attempts++;\n            }\n            long timeout = 2 << attempts;\n            timer.newTimeout(this, timeout, MILLISECONDS);\n        }\n\n        logger.warn(\"Disconnects with {}, port: {},host {}, reconnect: {}.\", ctx.channel(), port,host, doReconnect);\n\n        ctx.fireChannelInactive();\n    }\n\n    public void run(Timeout timeout) throws Exception {\n\n        ChannelFuture future;\n        synchronized (bootstrap) {\n            bootstrap.handler(new ChannelInitializer<Channel>() {\n\n                @Override\n                protected void initChannel(Channel ch) throws Exception {\n                    ch.pipeline().addLast(handlers());\n                }\n            });\n            future = bootstrap.connect(host,port);\n        }\n\n        future.addListener(new ChannelFutureListener() {\n\n            public void operationComplete(ChannelFuture f) throws Exception {\n                boolean succeed = f.isSuccess();\n\n                logger.warn(\"Reconnects with {}, {}.\", host+\":\"+port, succeed ? \"succeed\" : \"failed\");\n\n                if (!succeed) {\n                    f.channel().pipeline().fireChannelInactive();\n                }\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/production/client/connector/ClientConnector.java",
    "content": "package com.lyncc.netty.production.client.connector;\n\nimport io.netty.channel.Channel;\n\n/**\n * \n * @author BazingaLyn\n * @description\n * @time 2016年7月21日10:47:12\n * @modifytime\n */\npublic interface ClientConnector {\n\t\n\tChannel connect(int port,String host);\n\t\n\tvoid shutdownGracefully();\n\t\n}\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/production/client/connector/ConnectorIdleStateTrigger.java",
    "content": "package com.lyncc.netty.production.client.connector;\n\nimport io.netty.channel.ChannelHandler;\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.channel.ChannelInboundHandlerAdapter;\nimport io.netty.handler.timeout.IdleState;\nimport io.netty.handler.timeout.IdleStateEvent;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.lyncc.netty.production.common.Heartbeats;\n\n/**\n * 心跳trigger\n * @author BazingaLyn\n * @copyright fjc\n * @time\n */\n@ChannelHandler.Sharable\npublic class ConnectorIdleStateTrigger extends ChannelInboundHandlerAdapter {\n\t\n\tprivate static final Logger logger = LoggerFactory.getLogger(ConnectorIdleStateTrigger.class);\n\n    @Override\n    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {\n        if (evt instanceof IdleStateEvent) {\n            IdleState state = ((IdleStateEvent) evt).state();\n            if (state == IdleState.WRITER_IDLE) {\n            \tlogger.info(\"need send heartbeats\");\n                ctx.writeAndFlush(Heartbeats.heartbeatContent());\n            }\n        } else {\n            super.userEventTriggered(ctx, evt);\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/production/client/connector/DefaultCommonClientConnector.java",
    "content": "package com.lyncc.netty.production.client.connector;\n\nimport static com.lyncc.netty.production.common.NettyCommonProtocol.ACK;\nimport static com.lyncc.netty.production.common.NettyCommonProtocol.MAGIC;\nimport static com.lyncc.netty.production.common.NettyCommonProtocol.RESPONSE;\nimport static com.lyncc.netty.production.common.NettyCommonProtocol.SERVICE_1;\nimport static com.lyncc.netty.production.common.NettyCommonProtocol.SERVICE_2;\nimport static com.lyncc.netty.production.common.NettyCommonProtocol.SERVICE_3;\nimport static com.lyncc.netty.production.serializer.SerializerHolder.serializerImpl;\nimport static java.util.concurrent.TimeUnit.SECONDS;\nimport io.netty.bootstrap.Bootstrap;\nimport io.netty.buffer.ByteBuf;\nimport io.netty.channel.Channel;\nimport io.netty.channel.ChannelFuture;\nimport io.netty.channel.ChannelFutureListener;\nimport io.netty.channel.ChannelHandler;\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.channel.ChannelInboundHandlerAdapter;\nimport io.netty.channel.ChannelInitializer;\nimport io.netty.channel.ChannelOption;\nimport io.netty.channel.DefaultMessageSizeEstimator;\nimport io.netty.channel.EventLoopGroup;\nimport io.netty.channel.epoll.EpollEventLoopGroup;\nimport io.netty.channel.nio.NioEventLoopGroup;\nimport io.netty.channel.socket.nio.NioSocketChannel;\nimport io.netty.handler.codec.MessageToByteEncoder;\nimport io.netty.handler.codec.ReplayingDecoder;\nimport io.netty.handler.timeout.IdleStateHandler;\nimport io.netty.util.HashedWheelTimer;\n\nimport java.util.List;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\nimport java.util.concurrent.ThreadFactory;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.lyncc.netty.production.ConnectionWatchdog;\nimport com.lyncc.netty.production.common.Acknowledge;\nimport com.lyncc.netty.production.common.Message;\nimport com.lyncc.netty.production.common.NativeSupport;\nimport com.lyncc.netty.production.common.NettyCommonProtocol;\nimport com.lyncc.netty.production.common.exception.ConnectFailedException;\nimport com.lyncc.netty.production.srv.acceptor.AcknowledgeEncoder;\n\n/**\n * \n * @author BazingaLyn\n * @description 默认的一些比较常用的client的配置\n * @time 2016年7月22日14:54:37\n * @modifytime\n */\npublic class DefaultCommonClientConnector extends NettyClientConnector {\n\t\n\tprivate static final Logger logger = LoggerFactory.getLogger(DefaultCommonClientConnector.class);\n\t\n\t//每个连接维护一个channel\n\tprivate volatile Channel channel;\n\t\n\t//信息处理的handler\n\tprivate final MessageHandler handler = new MessageHandler();\n\t//编码\n    private final MessageEncoder encoder = new MessageEncoder();\n    //ack\n    private final AcknowledgeEncoder ackEncoder = new AcknowledgeEncoder();\n    \n    private final ConcurrentMap<Long, MessageNonAck> messagesNonAcks = new ConcurrentHashMap<Long, MessageNonAck>();\n\t\n\tprotected final HashedWheelTimer timer = new HashedWheelTimer(new ThreadFactory() {\n\t\t\n\t\tprivate AtomicInteger threadIndex = new AtomicInteger(0);\n\t\t\n\t\tpublic Thread newThread(Runnable r) {\n\t\t\treturn new Thread(r, \"NettyClientConnectorExecutor_\" + this.threadIndex.incrementAndGet());\n\t\t}\n\t});\n\t\n\t//心跳trigger\n\tprivate final ConnectorIdleStateTrigger idleStateTrigger = new ConnectorIdleStateTrigger();\n\n\tpublic DefaultCommonClientConnector() {\n\t\tinit();\n\t}\n\n\t@Override\n\tprotected void init() {\n\t\tsuper.init();\n\t\tbootstrap().option(ChannelOption.ALLOCATOR, allocator)\n\t\t.option(ChannelOption.MESSAGE_SIZE_ESTIMATOR, DefaultMessageSizeEstimator.DEFAULT)\n\t\t.option(ChannelOption.SO_REUSEADDR, true)\n\t\t.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, (int) SECONDS.toMillis(3))\n\t\t.channel(NioSocketChannel.class);\n\n\t\tbootstrap().option(ChannelOption.SO_KEEPALIVE, true)\n\t\t.option(ChannelOption.TCP_NODELAY, true)\n\t\t.option(ChannelOption.ALLOW_HALF_CLOSURE, false);\n\t\t\n\t}\n\n\tpublic Channel connect(int port, String host) {\n\t\t\n\t\tfinal Bootstrap boot = bootstrap();\n\t\t\n        // 重连watchdog\n        final ConnectionWatchdog watchdog = new ConnectionWatchdog(boot, timer, port,host) {\n\n            public ChannelHandler[] handlers() {\n                return new ChannelHandler[] {\n                \t\t//将自己[ConnectionWatchdog]装载到handler链中，当链路断掉之后，会触发ConnectionWatchdog #channelInActive方法\n                \t\t\n                        this,\n                        //每隔30s的时间触发一次userEventTriggered的方法，并且指定IdleState的状态位是WRITER_IDLE\n                        new IdleStateHandler(0, 30, 0, TimeUnit.SECONDS),\n                        //实现userEventTriggered方法，并在state是WRITER_IDLE的时候发送一个心跳包到sever端，告诉server端我还活着\n                        idleStateTrigger,\n                        new MessageDecoder(),\n                        encoder,\n                        ackEncoder,\n                        handler\n                };\n            }};\n        watchdog.setReconnect(true);\n\n        try {\n            ChannelFuture future;\n            synchronized (bootstrapLock()) {\n                boot.handler(new ChannelInitializer<NioSocketChannel>() {\n\n                    @Override\n                    protected void initChannel(NioSocketChannel ch) throws Exception {\n                        ch.pipeline().addLast(watchdog.handlers());\n                    }\n                });\n\n                future = boot.connect(\"127.0.0.1\", 20011);\n            }\n            future.sync();\n            channel = future.channel();\n        } catch (Throwable t) {\n            throw new ConnectFailedException(\"connects to [\" + host + \":\"+port+\"] fails\", t);\n        }\n\t\treturn channel;\n\t}\n\t\n\t@ChannelHandler.Sharable\n    class MessageHandler extends ChannelInboundHandlerAdapter {\n\t\t\n\t\t@Override\n\t\tpublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {\n\t\t\t\n\t\t\tif(msg instanceof Acknowledge){\n\t\t\t\tlogger.info(\"收到server端的Ack信息，无需再次发送信息\");\n\t\t\t\tmessagesNonAcks.remove(((Acknowledge)msg).sequence());\n\t\t\t}\n\t\t}\n\n    }\n\t\n\t/**\n     * **************************************************************************************************\n     *                                          Protocol\n     *  ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐\n     *       2   │   1   │    1   │     8     │      4      │\n     *  ├ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┤\n     *           │       │        │           │             │\n     *  │  MAGIC   Sign    Status   Invoke Id   Body Length                   Body Content              │\n     *           │       │        │           │             │\n     *  └ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘\n     *\n     * 消息头16个字节定长\n     * = 2 // MAGIC = (short) 0xbabe\n     * + 1 // 消息标志位, 用来表示消息类型\n     * + 1 // 空\n     * + 8 // 消息 id long 类型\n     * + 4 // 消息体body长度, int类型\n     */\n    @ChannelHandler.Sharable\n    static class MessageEncoder extends MessageToByteEncoder<Message> {\n\n        @Override\n        protected void encode(ChannelHandlerContext ctx, Message msg, ByteBuf out) throws Exception {\n            byte[] bytes = serializerImpl().writeObject(msg);\n\n            out.writeShort(MAGIC)\n                    .writeByte(msg.sign())\n                    .writeByte(0)\n                    .writeLong(0)\n                    .writeInt(bytes.length)\n                    .writeBytes(bytes);\n        }\n    }\n    \n    static class MessageDecoder extends ReplayingDecoder<MessageDecoder.State> {\n\n        public MessageDecoder() {\n            super(State.HEADER_MAGIC);\n        }\n\n        // 协议头\n        private final NettyCommonProtocol header = new NettyCommonProtocol();\n\n        @Override\n        protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {\n            switch (state()) {\n                case HEADER_MAGIC:\n                    checkMagic(in.readShort());             // MAGIC\n                    checkpoint(State.HEADER_SIGN);\n                case HEADER_SIGN:\n                    header.sign(in.readByte());             // 消息标志位\n                    checkpoint(State.HEADER_STATUS);\n                case HEADER_STATUS:\n                    in.readByte();                          // no-op\n                    checkpoint(State.HEADER_ID);\n                case HEADER_ID:\n                    header.id(in.readLong());               // 消息id\n                    checkpoint(State.HEADER_BODY_LENGTH);\n                case HEADER_BODY_LENGTH:\n                    header.bodyLength(in.readInt());        // 消息体长度\n                    checkpoint(State.BODY);\n                case BODY:\n                    switch (header.sign()) {\n                    \tcase RESPONSE:\n                        case SERVICE_1:\n                        case SERVICE_2:\n                        case SERVICE_3: {\n                            byte[] bytes = new byte[header.bodyLength()];\n                            in.readBytes(bytes);\n\n                            Message msg = serializerImpl().readObject(bytes, Message.class);\n                            msg.sign(header.sign());\n                            out.add(msg);\n\n                            break;\n                        }\n                        case ACK: {\n                            byte[] bytes = new byte[header.bodyLength()];\n                            in.readBytes(bytes);\n\n                            Acknowledge ack = serializerImpl().readObject(bytes, Acknowledge.class);\n                            out.add(ack);\n                            break;\n                        }\n                        default:\n                            throw new IllegalArgumentException();\n\n                    }\n                    checkpoint(State.HEADER_MAGIC);\n            }\n        }\n\n        private static void checkMagic(short magic) throws Exception {\n            if (MAGIC != magic) {\n                throw new IllegalArgumentException();\n            }\n        }\n\n        enum State {\n            HEADER_MAGIC,\n            HEADER_SIGN,\n            HEADER_STATUS,\n            HEADER_ID,\n            HEADER_BODY_LENGTH,\n            BODY\n        }\n    }\n\n\t@Override\n\tprotected EventLoopGroup initEventLoopGroup(int nWorkers, ThreadFactory workerFactory) {\n\t\treturn NativeSupport.isSupportNativeET() ? new EpollEventLoopGroup(nWorkers, workerFactory) : new NioEventLoopGroup(nWorkers, workerFactory);\n\t}\n\t\n\tpublic static class MessageNonAck {\n        private final long id;\n\n        private final Message msg;\n        private final Channel channel;\n        private final long timestamp = System.currentTimeMillis();\n\n        public MessageNonAck(Message msg, Channel channel) {\n            this.msg = msg;\n            this.channel = channel;\n\n            id = msg.sequence();\n        }\n    }\n\t\n\tprivate class AckTimeoutScanner implements Runnable {\n\n        public void run() {\n            for (;;) {\n                try {\n                    for (MessageNonAck m : messagesNonAcks.values()) {\n                        if (System.currentTimeMillis() - m.timestamp > SECONDS.toMillis(10)) {\n\n                            // 移除\n                            if (messagesNonAcks.remove(m.id) == null) {\n                                continue;\n                            }\n\n                            if (m.channel.isActive()) {\n                            \tlogger.warn(\"准备重新发送信息\");\n                                MessageNonAck msgNonAck = new MessageNonAck(m.msg, m.channel);\n                                messagesNonAcks.put(msgNonAck.id, msgNonAck);\n                                m.channel.writeAndFlush(m.msg)\n                                        .addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE);\n                            }\n                        }\n                    }\n\n                    Thread.sleep(300);\n                } catch (Throwable t) {\n                    logger.error(\"An exception has been caught while scanning the timeout acknowledges {}.\", t);\n                }\n            }\n        }\n    }\n\t\n\t{\n        Thread t = new Thread(new AckTimeoutScanner(), \"ack.timeout.scanner\");\n        t.setDaemon(true);\n        t.start();\n    }\n\n\n\tpublic void addNeedAckMessageInfo(MessageNonAck msgNonAck) {\n\t\t messagesNonAcks.put(msgNonAck.id, msgNonAck);\n\t}\n\t\n\n}\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/production/client/connector/NettyClientConnector.java",
    "content": "package com.lyncc.netty.production.client.connector;\n\nimport io.netty.bootstrap.Bootstrap;\nimport io.netty.buffer.ByteBufAllocator;\nimport io.netty.channel.EventLoopGroup;\nimport io.netty.util.concurrent.DefaultThreadFactory;\n\nimport java.util.concurrent.ThreadFactory;\n\npublic abstract class NettyClientConnector implements ClientConnector {\n\n\tpublic static final int AVAILABLE_PROCESSORS = Runtime.getRuntime().availableProcessors();\n\n\tprivate Bootstrap bootstrap;\n\tprivate EventLoopGroup worker;\n\tprivate int nWorkers;\n\n\tprotected volatile ByteBufAllocator allocator;\n\n\tpublic NettyClientConnector() {\n\t\tthis(AVAILABLE_PROCESSORS << 1);\n\t}\n\n\tpublic NettyClientConnector(int nWorkers) {\n\t\tthis.nWorkers = nWorkers;\n\t}\n\n\tprotected void init() {\n\t\tThreadFactory workerFactory = new DefaultThreadFactory(\"client.connector\");\n\t\tworker = initEventLoopGroup(nWorkers, workerFactory);\n\n\t\tbootstrap = new Bootstrap().group(worker);\n\n\t}\n\n\tprotected Bootstrap bootstrap() {\n\t\treturn bootstrap;\n\t}\n\n\tprotected Object bootstrapLock() {\n\t\treturn bootstrap;\n\t}\n\n\tpublic void shutdownGracefully() {\n\t\tworker.shutdownGracefully();\n\t}\n\n\tprotected abstract EventLoopGroup initEventLoopGroup(int nWorkers, ThreadFactory workerFactory);\n\n}\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/production/client/connector/package-info.java",
    "content": "/**\n * \n */\n/**\n * @author BazingaLyn\n * @description\n * @time\n * @modifytime\n */\npackage com.lyncc.netty.production.client.connector;"
  },
  {
    "path": "src/main/java/com/lyncc/netty/production/common/Acknowledge.java",
    "content": "/*\n * Copyright (c) 2015 The Jupiter Project\n *\n * Licensed under the Apache License, version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.lyncc.netty.production.common;\n\n/**\n * ACK确认\n *\n * jupiter\n * org.jupiter.transport\n *\n * @author jiachun.fjc\n */\npublic class Acknowledge {\n\n    public Acknowledge() {}\n\n    public Acknowledge(long sequence) {\n        this.sequence = sequence;\n    }\n\n    private long sequence; // ACK序号\n\n    public long sequence() {\n        return sequence;\n    }\n\n    public void sequence(long sequence) {\n        this.sequence = sequence;\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/production/common/Heartbeats.java",
    "content": "package com.lyncc.netty.production.common;\n\nimport static com.lyncc.netty.production.common.NettyCommonProtocol.HEAD_LENGTH;\nimport static com.lyncc.netty.production.common.NettyCommonProtocol.HEARTBEAT;\nimport static com.lyncc.netty.production.common.NettyCommonProtocol.MAGIC;\nimport io.netty.buffer.ByteBuf;\nimport io.netty.buffer.Unpooled;\n\n/**\n * \n * @author BazingaLyn\n * @description 心跳包\n * @time\n * @modifytime\n */\npublic class Heartbeats {\n\n    private static final ByteBuf HEARTBEAT_BUF;\n\n    static {\n        ByteBuf buf = Unpooled.buffer(HEAD_LENGTH);\n        buf.writeShort(MAGIC);\n        buf.writeByte(HEARTBEAT);\n        buf.writeByte(0);\n        buf.writeLong(0);\n        buf.writeInt(0);\n        HEARTBEAT_BUF = Unpooled.unmodifiableBuffer(Unpooled.unreleasableBuffer(buf));\n    }\n\n    public static ByteBuf heartbeatContent() {\n        return HEARTBEAT_BUF.duplicate();\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/production/common/Message.java",
    "content": "/*\n * Copyright (c) 2015 The Jupiter Project\n *\n * Licensed under the Apache License, version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.lyncc.netty.production.common;\n\nimport java.util.concurrent.atomic.AtomicLong;\n\n/**\n * 发布订阅信息的包装类.\n *\n * jupiter\n * org.jupiter.registry\n *\n * @author jiachun.fjc\n */\npublic class Message {\n\n    private static final AtomicLong sequenceGenerator = new AtomicLong(0);\n\n    private final long sequence;\n    private short sign;\n    private long version; // 版本号\n    private Object data;\n\n    public Message() {\n        this(sequenceGenerator.getAndIncrement());\n    }\n\n    public Message(long sequence) {\n        this.sequence = sequence;\n    }\n\n    public long sequence() {\n        return sequence;\n    }\n\n    public short sign() {\n        return sign;\n    }\n\n    public void sign(short sign) {\n        this.sign = sign;\n    }\n\n    public long getVersion() {\n        return version;\n    }\n\n    public void setVersion(long version) {\n        this.version = version;\n    }\n\n    public Object data() {\n        return data;\n    }\n\n    public void data(Object data) {\n        this.data = data;\n    }\n\n    @Override\n    public String toString() {\n        return \"Message{\" +\n                \"sequence=\" + sequence +\n                \", sign=\" + sign +\n                \", version=\" + version +\n                \", data=\" + data +\n                '}';\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/production/common/NativeSupport.java",
    "content": "package com.lyncc.netty.production.common;\n\n/**\n * \n * @author BazingaLyn\n * @description\n * @copyright fjc\n * @time 2016年7月20日20:48:08\n * @modifytime\n */\npublic final class NativeSupport {\n\n    private static final boolean SUPPORT_NATIVE_ET;\n\n    static {\n        boolean epoll;\n        try {\n            Class.forName(\"io.netty.channel.epoll.Native\");\n            epoll = true;\n        } catch (Throwable e) {\n            epoll = false;\n        }\n        SUPPORT_NATIVE_ET = epoll;\n    }\n\n    /**\n     * The native socket transport for Linux using JNI.\n     */\n    public static boolean isSupportNativeET() {\n        return SUPPORT_NATIVE_ET;\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/production/common/NettyCommonProtocol.java",
    "content": "package com.lyncc.netty.production.common;\n\n/**\n * \n * @author BazingaLyn\n * @description Netty的C/S端的之间约定的协议\n * @time 2016年7月27日09:20:55\n * @modifytime\n */\npublic class NettyCommonProtocol {\n\t\n\t/** 协议头长度 */\n    public static final int HEAD_LENGTH = 16;\n    /** Magic */\n    public static final short MAGIC = (short) 0xbabe;\n\n\n    /** Request */\n    public static final byte REQUEST = 1;\n    /** Response */\n    public static final byte RESPONSE = 2;\n\n    public static final byte SERVICE_1 = 3;\n    public static final byte SERVICE_2 = 4;\n    public static final byte SERVICE_3 = 5;\n    public static final byte SERVICE_4 = 6;\n\n    /** Acknowledge */\n    public static final byte ACK = 126;\n    /** Heartbeat */\n    public static final byte HEARTBEAT = 127;\n\n    private byte sign;\n    private byte status;\n    private long id;\n    private int bodyLength;\n\n    public byte sign() {\n        return sign;\n    }\n\n    public void sign(byte sign) {\n        this.sign = sign;\n    }\n\n    public byte status() {\n        return status;\n    }\n\n    public void status(byte status) {\n        this.status = status;\n    }\n\n    public long id() {\n        return id;\n    }\n\n    public void id(long id) {\n        this.id = id;\n    }\n\n    public int bodyLength() {\n        return bodyLength;\n    }\n\n    public void bodyLength(int bodyLength) {\n        this.bodyLength = bodyLength;\n    }\n\n\t@Override\n\tpublic String toString() {\n\t\treturn \"NettyCommonProtocol [sign=\" + sign + \", status=\" + status + \", id=\" + id + \", bodyLength=\" + bodyLength + \"]\";\n\t}\n\n}\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/production/common/NettyEvent.java",
    "content": "/**\n * Copyright (C) 2010-2013 Alibaba Group Holding Limited\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lyncc.netty.production.common;\n\nimport io.netty.channel.Channel;\n\n\n/**\n * Netty产生的各种事件\n * \n * @author shijia.wxr<vintage.wang@gmail.com>\n * @since 2013-7-13\n */\npublic class NettyEvent {\n    private final NettyEventType type;\n    private final String remoteAddr;\n    private final Channel channel;\n\n\n    public NettyEvent(NettyEventType type, String remoteAddr, Channel channel) {\n        this.type = type;\n        this.remoteAddr = remoteAddr;\n        this.channel = channel;\n    }\n\n\n    public NettyEventType getType() {\n        return type;\n    }\n\n\n    public String getRemoteAddr() {\n        return remoteAddr;\n    }\n\n\n    public Channel getChannel() {\n        return channel;\n    }\n\n\n    @Override\n    public String toString() {\n        return \"NettyEvent [type=\" + type + \", remoteAddr=\" + remoteAddr + \", channel=\" + channel + \"]\";\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/production/common/NettyEventType.java",
    "content": "/**\n * Copyright (C) 2010-2013 Alibaba Group Holding Limited\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.lyncc.netty.production.common;\n\n/**\n * Netty产生的事件类型\n * \n * @author shijia.wxr<vintage.wang@gmail.com>\n * @since 2013-7-13\n */\npublic enum NettyEventType {\n    CONNECT,\n    CLOSE,\n    IDLE,\n    EXCEPTION\n}\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/production/common/ServiceThread.java",
    "content": "package com.lyncc.netty.production.common;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n\npublic abstract class ServiceThread implements Runnable {\n    private static final Logger stlog = LoggerFactory.getLogger(ServiceThread.class);\n    protected final Thread thread;\n    private static final long JoinTime = 90 * 1000;\n    protected volatile boolean hasNotified = false;\n    protected volatile boolean stoped = false;\n\n\n    public ServiceThread() {\n        this.thread = new Thread(this, this.getServiceName());\n    }\n\n\n    public abstract String getServiceName();\n\n\n    public void start() {\n        this.thread.start();\n    }\n\n\n    public void shutdown() {\n        this.shutdown(false);\n    }\n\n\n    public void stop() {\n        this.stop(false);\n    }\n\n\n    public void makeStop() {\n        this.stoped = true;\n        stlog.info(\"makestop thread \" + this.getServiceName());\n    }\n\n\n    public void stop(final boolean interrupt) {\n        this.stoped = true;\n        stlog.info(\"stop thread \" + this.getServiceName() + \" interrupt \" + interrupt);\n        synchronized (this) {\n            if (!this.hasNotified) {\n                this.hasNotified = true;\n                this.notify();\n            }\n        }\n\n        if (interrupt) {\n            this.thread.interrupt();\n        }\n    }\n\n\n    public void shutdown(final boolean interrupt) {\n        this.stoped = true;\n        stlog.info(\"shutdown thread \" + this.getServiceName() + \" interrupt \" + interrupt);\n        synchronized (this) {\n            if (!this.hasNotified) {\n                this.hasNotified = true;\n                this.notify();\n            }\n        }\n\n        try {\n            if (interrupt) {\n                this.thread.interrupt();\n            }\n\n            long beginTime = System.currentTimeMillis();\n            this.thread.join(this.getJointime());\n            long eclipseTime = System.currentTimeMillis() - beginTime;\n            stlog.info(\"join thread \" + this.getServiceName() + \" eclipse time(ms) \" + eclipseTime + \" \"\n                    + this.getJointime());\n        } catch (InterruptedException e) {\n            e.printStackTrace();\n        }\n    }\n\n\n    public void wakeup() {\n        synchronized (this) {\n            if (!this.hasNotified) {\n                this.hasNotified = true;\n                this.notify();\n            }\n        }\n    }\n\n\n    protected void waitForRunning(long interval) {\n        synchronized (this) {\n            if (this.hasNotified) {\n                this.hasNotified = false;\n                this.onWaitEnd();\n                return;\n            }\n\n            try {\n                this.wait(interval);\n            } catch (InterruptedException e) {\n                e.printStackTrace();\n            } finally {\n                this.hasNotified = false;\n                this.onWaitEnd();\n            }\n        }\n    }\n\n\n    protected void onWaitEnd() {\n    }\n\n\n    public boolean isStoped() {\n        return stoped;\n    }\n\n\n    public long getJointime() {\n        return JoinTime;\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/production/common/exception/ConnectFailedException.java",
    "content": "/*\n * Copyright (c) 2015 The Jupiter Project\n *\n * Licensed under the Apache License, version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.lyncc.netty.production.common.exception;\n\n/**\n * jupiter\n * org.jupiter.transport.exception\n *\n * @author jiachun.fjc\n */\npublic class ConnectFailedException extends RuntimeException {\n\n    private static final long serialVersionUID = -2890742743547564900L;\n\n    public ConnectFailedException() {\n        super();\n    }\n\n    public ConnectFailedException(String message) {\n        super(message);\n    }\n\n    public ConnectFailedException(String message, Throwable cause) {\n        super(message, cause);\n    }\n\n    public ConnectFailedException(Throwable cause) {\n        super(cause);\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/production/common/package-info.java",
    "content": "/**\n * @author BazingaLyn\n * @description 一些用的基本类\n * @time 2016年7月20日16:50:10\n * @modifytime\n */\npackage com.lyncc.netty.production.common;"
  },
  {
    "path": "src/main/java/com/lyncc/netty/production/example/ClientConnectorStartup.java",
    "content": "package com.lyncc.netty.production.example;\n\nimport static com.lyncc.netty.production.common.NettyCommonProtocol.REQUEST;\nimport io.netty.channel.Channel;\nimport io.netty.channel.ChannelFuture;\nimport io.netty.channel.ChannelFutureListener;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.lyncc.netty.production.client.connector.DefaultCommonClientConnector;\nimport com.lyncc.netty.production.client.connector.DefaultCommonClientConnector.MessageNonAck;\nimport com.lyncc.netty.production.common.Message;\nimport com.lyncc.netty.production.srv.acceptor.DefaultCommonSrvAcceptor;\n\n/**\n * \n * @author BazingaLyn\n * @description 客户链接端 启动类\n * @time 2016年7月22日14:53:32\n * @modifytime\n */\npublic class ClientConnectorStartup {\n\t\n\tprivate static final Logger logger = LoggerFactory.getLogger(DefaultCommonSrvAcceptor.class);\n\t\n\tpublic static void main(String[] args) {\n\t\t\n\t\tDefaultCommonClientConnector clientConnector = new DefaultCommonClientConnector();\n\t\tChannel channel = clientConnector.connect(20011, \"127.0.0.1\");\n\t\tUser user = new User(1, \"dubbo\");\n\t\tMessage message = new Message();\n\t\tmessage.sign(REQUEST);\n\t\tmessage.data(user);\n\t\t//获取到channel发送双方规定的message格式的信息\n\t\tchannel.writeAndFlush(message).addListener(new ChannelFutureListener() {\n\t\t\t\n\t\t\tpublic void operationComplete(ChannelFuture future) throws Exception {\n\t\t\t\t if(!future.isSuccess()) {  \n\t                    logger.info(\"send fail,reason is {}\",future.cause().getMessage());  \n\t                } \n\t\t\t}\n\t\t});\n\t\t//防止对象处理发生异常的情况\n\t\tMessageNonAck msgNonAck = new MessageNonAck(message, channel);\n\t\tclientConnector.addNeedAckMessageInfo(msgNonAck);\n\t}\n\t\n\tpublic static class User {\n\t\t\n\t\tprivate Integer id;\n\t\t\n\t\tprivate String username;\n\t\t\n\n\t\tpublic User(Integer id, String username) {\n\t\t\tthis.id = id;\n\t\t\tthis.username = username;\n\t\t}\n\n\t\tpublic Integer getId() {\n\t\t\treturn id;\n\t\t}\n\n\t\tpublic void setId(Integer id) {\n\t\t\tthis.id = id;\n\t\t}\n\n\t\tpublic String getUsername() {\n\t\t\treturn username;\n\t\t}\n\n\t\tpublic void setUsername(String username) {\n\t\t\tthis.username = username;\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn \"User [id=\" + id + \", username=\" + username + \"]\";\n\t\t}\n\t\t\n\t}\n\n}\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/production/example/SrvAcceptorStartup.java",
    "content": "package com.lyncc.netty.production.example;\n\nimport com.lyncc.netty.production.srv.acceptor.DefaultCommonSrvAcceptor;\n\npublic class SrvAcceptorStartup {\n\t\n\tpublic static void main(String[] args) throws InterruptedException {\n\t\t\n\t\tDefaultCommonSrvAcceptor defaultCommonSrvAcceptor = new DefaultCommonSrvAcceptor(20011,null);\n\t\tdefaultCommonSrvAcceptor.start();\n\t\t\n\t}\n\n}\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/production/example/package-info.java",
    "content": "/**\n * \n */\n/**\n * @author BazingaLyn\n * @description 测试包\n * @time 2016年7月27日08:58:55\n * @modifytime\n */\npackage com.lyncc.netty.production.example;"
  },
  {
    "path": "src/main/java/com/lyncc/netty/production/serializer/Serializer.java",
    "content": "package com.lyncc.netty.production.serializer;\n\n\n/**\n * \n * @author BazingaLyn\n * @description 序列化工具接口\n * @time 2016年7月26日18:53:48\n * @modifytime\n */\npublic interface Serializer {\n\n\t/**\n\t * 将obj序列化成byte数组\n\t * @param obj\n\t * @return\n\t */\n    <T> byte[] writeObject(T obj);\n\n    /**\n     * 将byte数组反序列化成class是clazz的obj对象\n     * @param bytes\n     * @param clazz\n     * @return\n     */\n    <T> T readObject(byte[] bytes, Class<T> clazz);\n}\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/production/serializer/SerializerHolder.java",
    "content": "\npackage com.lyncc.netty.production.serializer;\n\nimport com.lyncc.netty.production.serializer.protostuff.ProtoStuffSerializer;\n\n\n/**\n * \n * @author BazingaLyn\n * @description 序列化工具 obj to byte 用于网络传输\n * @time 2016年7月26日18:51:43\n * @modifytime\n */\npublic final class SerializerHolder {\n\n\t//使用google的protostuff\n\t//protostuff 是一个支持各种格式的一个序列化Java类库，包括 JSON、XML、YAML等格式。\n    private static final Serializer serializer = new ProtoStuffSerializer();\n\n    public static Serializer serializerImpl() {\n        return serializer;\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/production/serializer/protostuff/ProtoStuffSerializer.java",
    "content": "package com.lyncc.netty.production.serializer.protostuff;\n\nimport io.protostuff.LinkedBuffer;\nimport io.protostuff.ProtostuffIOUtil;\nimport io.protostuff.Schema;\nimport io.protostuff.runtime.RuntimeSchema;\n\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\n\nimport org.objenesis.Objenesis;\nimport org.objenesis.ObjenesisStd;\n\nimport com.lyncc.netty.production.serializer.Serializer;\n\n/**\n * 具体实现\n * @author BazingaLyn\n * @description\n * @time 2016年7月26日18:55:54\n * @modifytime\n */\npublic class ProtoStuffSerializer implements Serializer {\n\n\tprivate static Map<Class<?>, Schema<?>> cachedSchema = new ConcurrentHashMap<Class<?>, Schema<?>>();\n\n\tprivate static Objenesis objenesis = new ObjenesisStd(true);\n\n\t@SuppressWarnings(\"unchecked\")\n\tpublic <T> byte[] writeObject(T obj) {\n\n\t\tClass<T> cls = (Class<T>) obj.getClass();\n\t\tLinkedBuffer buffer = LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE);\n\t\ttry {\n\t\t\tSchema<T> schema = getSchema(cls);\n\t\t\treturn ProtostuffIOUtil.toByteArray(obj, schema, buffer);\n\t\t} catch (Exception e) {\n\t\t\tthrow new IllegalStateException(e.getMessage(), e);\n\t\t} finally {\n\t\t\tbuffer.clear();\n\t\t}\n\t}\n\n\tpublic <T> T readObject(byte[] bytes, Class<T> clazz) {\n\t\ttry {\n\t\t\tT message = objenesis.newInstance(clazz);\n\t\t\tSchema<T> schema = getSchema(clazz);\n\t\t\tProtostuffIOUtil.mergeFrom(bytes, message, schema);\n\t\t\treturn message;\n\t\t} catch (Exception e) {\n\t\t\tthrow new IllegalStateException(e.getMessage(), e);\n\t\t}\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate static <T> Schema<T> getSchema(Class<T> cls) {\n\t\tSchema<T> schema = (Schema<T>) cachedSchema.get(cls);\n\t\tif (schema == null) {\n\t\t\tschema = RuntimeSchema.createFrom(cls);\n\t\t\tcachedSchema.put(cls, schema);\n\t\t}\n\t\treturn schema;\n\t}\n}\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/production/srv/acceptor/AcceptorIdleStateTrigger.java",
    "content": "package com.lyncc.netty.production.srv.acceptor;\n\nimport io.netty.channel.ChannelHandler;\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.channel.ChannelInboundHandlerAdapter;\nimport io.netty.handler.timeout.IdleState;\nimport io.netty.handler.timeout.IdleStateEvent;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * \n * @author BazingaLyn\n * @description\n * @time\n * @modifytime 2016年7月21日09:39:22\n */\n@ChannelHandler.Sharable\npublic class AcceptorIdleStateTrigger extends ChannelInboundHandlerAdapter {\n\t\n\tprivate static final Logger logger = LoggerFactory.getLogger(AcceptorIdleStateTrigger.class);\n\n    @Override\n    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {\n        if (evt instanceof IdleStateEvent) {\n            IdleState state = ((IdleStateEvent) evt).state();\n            if (state == IdleState.READER_IDLE) {\n            \tlogger.error(\"occor exception\");\n                throw new Exception(\"NO SIGNAL\");\n            }\n        } else {\n            super.userEventTriggered(ctx, evt);\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/production/srv/acceptor/AcknowledgeEncoder.java",
    "content": "package com.lyncc.netty.production.srv.acceptor;\n\nimport static com.lyncc.netty.production.common.NettyCommonProtocol.ACK;\nimport static com.lyncc.netty.production.common.NettyCommonProtocol.MAGIC;\nimport static com.lyncc.netty.production.serializer.SerializerHolder.serializerImpl;\nimport io.netty.buffer.ByteBuf;\nimport io.netty.channel.ChannelHandler;\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.handler.codec.MessageToByteEncoder;\n\nimport com.lyncc.netty.production.common.Acknowledge;\n\n\n/**\n * \n * @author BazingaLyn\n * @description ack的编码器\n * @time\n * @modifytime\n */\n@ChannelHandler.Sharable\npublic class AcknowledgeEncoder extends MessageToByteEncoder<Acknowledge> {\n\n    @Override\n    protected void encode(ChannelHandlerContext ctx, Acknowledge ack, ByteBuf out) throws Exception {\n        byte[] bytes = serializerImpl().writeObject(ack);\n        out.writeShort(MAGIC)\n                .writeByte(ACK)\n                .writeByte(0)\n                .writeLong(ack.sequence())\n                .writeInt(bytes.length)\n                .writeBytes(bytes);\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/production/srv/acceptor/ChannelEventListener.java",
    "content": "package com.lyncc.netty.production.srv.acceptor;\n\nimport io.netty.channel.Channel;\n\n\npublic interface ChannelEventListener {\n    void onChannelConnect(final String remoteAddr, final Channel channel);\n\n\n    void onChannelClose(final String remoteAddr, final Channel channel);\n\n\n    void onChannelException(final String remoteAddr, final Channel channel);\n\n\n    void onChannelIdle(final String remoteAddr, final Channel channel);\n}\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/production/srv/acceptor/DefaultCommonSrvAcceptor.java",
    "content": "package com.lyncc.netty.production.srv.acceptor;\n\nimport static com.lyncc.netty.production.common.NettyCommonProtocol.HEARTBEAT;\nimport static com.lyncc.netty.production.common.NettyCommonProtocol.MAGIC;\nimport static com.lyncc.netty.production.common.NettyCommonProtocol.REQUEST;\nimport static com.lyncc.netty.production.common.NettyCommonProtocol.SERVICE_1;\nimport static com.lyncc.netty.production.common.NettyCommonProtocol.SERVICE_2;\nimport static com.lyncc.netty.production.common.NettyCommonProtocol.SERVICE_3;\nimport static com.lyncc.netty.production.common.NettyCommonProtocol.SERVICE_4;\nimport static com.lyncc.netty.production.serializer.SerializerHolder.serializerImpl;\nimport io.netty.bootstrap.ServerBootstrap;\nimport io.netty.buffer.ByteBuf;\nimport io.netty.channel.Channel;\nimport io.netty.channel.ChannelDuplexHandler;\nimport io.netty.channel.ChannelFuture;\nimport io.netty.channel.ChannelFutureListener;\nimport io.netty.channel.ChannelHandler;\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.channel.ChannelInitializer;\nimport io.netty.channel.ChannelOption;\nimport io.netty.channel.ChannelPromise;\nimport io.netty.channel.EventLoopGroup;\nimport io.netty.channel.SimpleChannelInboundHandler;\nimport io.netty.channel.epoll.EpollEventLoopGroup;\nimport io.netty.channel.nio.NioEventLoopGroup;\nimport io.netty.channel.socket.SocketChannel;\nimport io.netty.channel.socket.nio.NioServerSocketChannel;\nimport io.netty.handler.codec.MessageToByteEncoder;\nimport io.netty.handler.codec.ReplayingDecoder;\nimport io.netty.handler.timeout.IdleStateHandler;\nimport io.netty.util.Signal;\n\nimport java.net.InetSocketAddress;\nimport java.net.SocketAddress;\nimport java.util.List;\nimport java.util.concurrent.ThreadFactory;\nimport java.util.concurrent.TimeUnit;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.lyncc.netty.production.common.Acknowledge;\nimport com.lyncc.netty.production.common.Message;\nimport com.lyncc.netty.production.common.NativeSupport;\nimport com.lyncc.netty.production.common.NettyCommonProtocol;\nimport com.lyncc.netty.production.common.NettyEvent;\nimport com.lyncc.netty.production.common.NettyEventType;\n\n/**\n * \n * @author BazingaLyn\n * @description 基本的常用的netty Server配置\n * @time 2016年7月20日20:49:53\n * @modifytime\n */\npublic class DefaultCommonSrvAcceptor extends DefaultSrvAcceptor {\n\t\n\n\tprivate static final Logger logger = LoggerFactory.getLogger(DefaultCommonSrvAcceptor.class);\n\t\n\t//acceptor的trigger\n\tprivate final AcceptorIdleStateTrigger idleStateTrigger = new AcceptorIdleStateTrigger();\n\t\n\t//message的编码器\n\tprivate final MessageEncoder encoder = new MessageEncoder();\n\t\n\t//Ack的编码器\n\tprivate final AcknowledgeEncoder ackEncoder = new AcknowledgeEncoder();\n\t\n\t//SimpleChannelInboundHandler类型的handler只处理@{link Message}类型的数据\n\tprivate final MessageHandler handler = new MessageHandler();\n\t\n\tprivate final ChannelEventListener channelEventListener;\n\n\tpublic DefaultCommonSrvAcceptor(int port,ChannelEventListener channelEventListener) {\n\t\tsuper(new InetSocketAddress(port));\n\t\tthis.init();\n\t\tthis.channelEventListener = channelEventListener;\n\t}\n\t\n\t@Override\n\tprotected void init() {\n\t\tsuper.init();\n\t\t\n\t\t/**\n\t\t * backlog参数的含义:\n\t\t * 一个未完成连接的队列，此队列维护着那些已收到了客户端SYN分节信息，等待完成三路握手的连接，socket的状态是SYN_RCVD\n\t\t * .一个已完成的连接的队列，此队列包含了那些已经完成三路握手的连接，socket的状态是ESTABLISHED\n\t\t * backlog参数历史上被定义为上面两个队列的大小之和\n\t\t * 当客户端的第一个SYN到达的时候，TCP会在未完成队列中增加一个新的记录然后回复给客户端三路握手中的第二个分节(服务端的SYN和针对客户端的ACK)\n\t\t * ，这条记录会在未完成队列中一直存在，直到三路握手中的最后一个分节到达，或者直到超时(Berkeley时间将这个超时定义为75秒)\n\t\t * 如果当客户端SYN到达的时候队列已满，TCP将会忽略后续到达的SYN，但是不会给客户端发送RST信息，因为此时允许客户端重传SYN分节，如果返回错误\n\t\t * 信息，那么客户端将无法分清到底是服务端对应端口上没有相应应用程序还是服务端对应端口上队列已满这两种情况\n\t\t */\n\t\tbootstrap().option(ChannelOption.SO_BACKLOG, 32768)\n\t\t/**\n\t     * [TCP/IP协议详解]中描述:\n\t     * 当TCP执行一个主动关闭, 并发回最后一个ACK ,该连接必须在TIME_WAIT状态停留的时间为2倍的MSL.\n\t     * 这样可让TCP再次发送最后的ACK以防这个ACK丢失(另一端超时并重发最后的FIN).\n\t     * 这种2MSL等待的另一个结果是这个TCP连接在2MSL等待期间, 定义这个连接的插口对(TCP四元组)不能再被使用.\n\t     * 这个连接只能在2MSL结束后才能再被使用.\n\t     *\n\t     * 许多具体的实现中允许一个进程重新使用仍处于2MSL等待的端口(通常是设置选项SO_REUSEADDR),\n\t     * 但TCP不能允许一个新的连接建立在相同的插口对上。\n\t     */\n\t\t.option(ChannelOption.SO_REUSEADDR, true)\n\t\t//\n\t\t.childOption(ChannelOption.SO_REUSEADDR, true)\n\t\t/**\n\t     * 为TCP套接字设置keepalive选项时, 如果在2个小时（实际值与具体实现有关）内在\n\t     * 任意方向上都没有跨越套接字交换数据, 则 TCP 会自动将 keepalive 探头发送到对端.\n\t     * 此探头是对端必须响应的TCP段.\n\t     *\n\t     * 期望的响应为以下三种之一:\n\t     * 1. 收到期望的对端ACK响应\n\t     *      不通知应用程序(因为一切正常), 在另一个2小时的不活动时间过后，TCP将发送另一个探头。\n\t     * 2. 对端响应RST\n\t     *      通知本地TCP对端已崩溃并重新启动, 套接字被关闭.\n\t     * 3. 对端没有响\n\t     *      套接字被关闭。\n\t     *\n\t     * 此选项的目的是检测对端主机是否崩溃, 仅对TCP套接字有效.\n\t     */\n\t\t.childOption(ChannelOption.SO_KEEPALIVE, true)\n\t\t/**\n\t     * 对此连接禁用 Nagle 算法.\n\t     * 在确认以前的写入数据之前不会缓冲写入网络的数据. 仅对TCP有效.\n\t     *\n\t     * Nagle算法试图减少TCP包的数量和结构性开销, 将多个较小的包组合成较大的包进行发送.\n\t     * 但这不是重点, 关键是这个算法受TCP延迟确认影响, 会导致相继两次向连接发送请求包,\n\t     * 读数据时会有一个最多达500毫秒的延时.\n\t     *\n\t     * 这叫做“ACK delay”, 解决办法是设置TCP_NODELAY。\n\t     */\n        .childOption(ChannelOption.TCP_NODELAY, true)\n        /**\n         * 禁用掉半关闭的状态的链接状态\n         * TCP四次握手关闭连接的时候，step2-step3中出现的状态\n         */\n        .childOption(ChannelOption.ALLOW_HALF_CLOSURE, false);\n\t\t\n\t}\n\n\n\t@Override\n\tprotected EventLoopGroup initEventLoopGroup(int nthread, ThreadFactory bossFactory) {\n\t\treturn NativeSupport.isSupportNativeET() ? new EpollEventLoopGroup(nthread, bossFactory) : new NioEventLoopGroup(nthread, bossFactory);\n\t}\n\n\n\t@Override\n\tprotected ChannelFuture bind(SocketAddress localAddress) {\n\t\tServerBootstrap boot = bootstrap();\n\t\t\n\t\tboot.channel(NioServerSocketChannel.class)\n        .childHandler(new ChannelInitializer<SocketChannel>() {\n\n            @Override\n            protected void initChannel(SocketChannel ch) throws Exception {\n                ch.pipeline().addLast(\n                \t\t//每隔60s的时间内如果没有接受到任何的read事件的话，则会触发userEventTriggered事件，并指定IdleState的类型为READER_IDLE\n                \t\tnew IdleStateHandler(60, 0, 0, TimeUnit.SECONDS),\n                \t\t//因为我们在client端设置了每隔30s会发送一个心跳包过来，如果60s都没有收到心跳，则说明链路发生了问题\n                        idleStateTrigger,\n                        //message的解码器\n                        new MessageDecoder(),\n                        encoder,\n                        ackEncoder,\n                        new NettyConnetManageHandler(),\n                        handler);\n            }\n        });\n\t\t\n\t\treturn boot.bind(localAddress);\n\t}\n\t\n\t/**\n\t * 解码器，继承于ReplayingDecoder\n\t * @author BazingaLyn\n\t * @description \n\t * @time\n\t * @modifytime\n\t */\n\t/**\n     * **************************************************************************************************\n     *                                          Protocol\n     *  ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐\n     *       2   │   1   │    1   │     8     │      4      │\n     *  ├ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┤\n     *           │       │        │           │             │\n     *  │  MAGIC   Sign    Status   Invoke Id   Body Length                   Body Content              │\n     *           │       │        │           │             │\n     *  └ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘\n     *\n     * 消息头16个字节定长\n     * = 2 // MAGIC = (short) 0xbabe\n     * + 1 // 消息标志位, 用来表示消息类型\n     * + 1 // 空\n     * + 8 // 消息 id long 类型\n     * + 4 // 消息体body长度, int类型\n     */\n\tstatic class MessageDecoder extends ReplayingDecoder<MessageDecoder.State> {\n\n\t\t//构造函数 设置初始的枚举类型是什么\n        public MessageDecoder() {\n            super(State.HEADER_MAGIC);\n        }\n\n        // 协议头\n        private final NettyCommonProtocol header = new NettyCommonProtocol();\n\n        @Override\n        protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {\n            switch (state()) {\n                case HEADER_MAGIC:\n                    checkMagic(in.readShort());             // MAGIC\n                    checkpoint(State.HEADER_SIGN);\n                case HEADER_SIGN:\n                    header.sign(in.readByte());             // 消息标志位\n                    checkpoint(State.HEADER_STATUS);\n                case HEADER_STATUS:\n                    in.readByte();                          // no-op\n                    checkpoint(State.HEADER_ID);\n                case HEADER_ID:\n                    header.id(in.readLong());               // 消息id\n                    checkpoint(State.HEADER_BODY_LENGTH);\n                case HEADER_BODY_LENGTH:\n                    header.bodyLength(in.readInt());        // 消息体长度\n                    checkpoint(State.BODY);\n                case BODY:\n                    switch (header.sign()) {\n                        case HEARTBEAT:\n                            break;\n                        case REQUEST:\n                        case SERVICE_1:\n                        case SERVICE_2:\n                        case SERVICE_3:\n                        case SERVICE_4: {\n                            byte[] bytes = new byte[header.bodyLength()];\n                            in.readBytes(bytes);\n\n                            Message msg = serializerImpl().readObject(bytes, Message.class);\n                            msg.sign(header.sign());\n                            out.add(msg);\n\n                            break;\n                        }\n                        default:\n                            throw new IllegalAccessException();\n                    }\n                    checkpoint(State.HEADER_MAGIC);\n            }\n        }\n        private static void checkMagic(short magic) throws Signal {\n            if (MAGIC != magic) {\n                throw new IllegalArgumentException();\n            }\n        }\n\n        enum State {\n            HEADER_MAGIC,\n            HEADER_SIGN,\n            HEADER_STATUS,\n            HEADER_ID,\n            HEADER_BODY_LENGTH,\n            BODY\n        }\n\t}\n\t\n\t/**\n     * **************************************************************************************************\n     *                                          Protocol\n     *  ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐\n     *       2   │   1   │    1   │     8     │      4      │\n     *  ├ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┤\n     *           │       │        │           │             │\n     *  │  MAGIC   Sign    Status   Invoke Id   Body Length                   Body Content              │\n     *           │       │        │           │             │\n     *  └ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘\n     *\n     * 消息头16个字节定长\n     * = 2 // MAGIC = (short) 0xbabe\n     * + 1 // 消息标志位, 用来表示消息类型\n     * + 1 // 空\n     * + 8 // 消息 id long 类型\n     * + 4 // 消息体body长度, int类型\n     */\n    @ChannelHandler.Sharable\n    static class MessageEncoder extends MessageToByteEncoder<Message> {\n\n        @Override\n        protected void encode(ChannelHandlerContext ctx, Message msg, ByteBuf out) throws Exception {\n            byte[] bytes = serializerImpl().writeObject(msg);\n            out.writeShort(MAGIC)\n                    .writeByte(msg.sign())\n                    .writeByte(0)\n                    .writeLong(0)\n                    .writeInt(bytes.length)\n                    .writeBytes(bytes);\n        }\n    }\n    \n    @ChannelHandler.Sharable\n    class MessageHandler extends SimpleChannelInboundHandler<Message> {\n    \t\n\t\t@Override\n\t\tprotected void channelRead0(ChannelHandlerContext ctx, Message message) throws Exception {\n\t\t\tChannel channel = ctx.channel();\n\t\t\tlogger.info(message.toString());\n    \t\t\n    \t\t// 接收到发布信息的时候，要给Client端回复ACK\n\t\t\tchannel.writeAndFlush(new Acknowledge(message.sequence())).addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE);\n\t\t}\n    }\n    \n    class NettyConnetManageHandler extends ChannelDuplexHandler {\n    \t\n    \t@Override\n    \tpublic void connect(ChannelHandlerContext ctx, SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise future) throws Exception {\n    \t\tfinal String local = localAddress == null ? \"UNKNOW\" : localAddress.toString();\n            final String remote = remoteAddress == null ? \"UNKNOW\" : remoteAddress.toString();\n            logger.info(\"NETTY CLIENT PIPELINE: CONNECT  {} => {}\", local, remote);\n    \t\tsuper.connect(ctx, remoteAddress, localAddress, future);\n    \t\t\n    \t\tif (DefaultCommonSrvAcceptor.this.channelEventListener != null) {\n    \t\t\tDefaultCommonSrvAcceptor.this.putNettyEvent(new NettyEvent(NettyEventType.CONNECT, remoteAddress\n                    .toString(), ctx.channel()));\n            }\n    \t}\n    \t\n    \t@Override\n    \tpublic void disconnect(ChannelHandlerContext ctx, ChannelPromise future) throws Exception {\n    \t\tfinal String remoteAddress = ctx.channel().remoteAddress().toString();\n            logger.info(\"NETTY CLIENT PIPELINE: DISCONNECT {}\", remoteAddress);\n            super.disconnect(ctx, future);\n\n            if (DefaultCommonSrvAcceptor.this.channelEventListener != null) {\n            \tDefaultCommonSrvAcceptor.this.putNettyEvent(new NettyEvent(NettyEventType.CLOSE, remoteAddress\n                    .toString(), ctx.channel()));\n            }\n    \t}\n    \t\n    \t@Override\n        public void close(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception {\n            final String remoteAddress = ctx.channel().remoteAddress().toString();\n            logger.info(\"NETTY CLIENT PIPELINE: CLOSE {}\", remoteAddress);\n            super.close(ctx, promise);\n\n            if (DefaultCommonSrvAcceptor.this.channelEventListener != null) {\n            \tDefaultCommonSrvAcceptor.this.putNettyEvent(new NettyEvent(NettyEventType.CLOSE, remoteAddress\n                    .toString(), ctx.channel()));\n            }\n        }\n\n\n        @Override\n        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {\n            final String remoteAddress = ctx.channel().remoteAddress().toString();\n            logger.warn(\"NETTY CLIENT PIPELINE: exceptionCaught {}\", remoteAddress);\n            logger.warn(\"NETTY CLIENT PIPELINE: exceptionCaught exception.\", cause);\n            if (DefaultCommonSrvAcceptor.this.channelEventListener != null) {\n            \tDefaultCommonSrvAcceptor.this.putNettyEvent(new NettyEvent(NettyEventType.EXCEPTION, remoteAddress\n                    .toString(), ctx.channel()));\n            }\n        }\n    }\n\n\t@Override\n\tprotected ChannelEventListener getChannelEventListener() {\n\t\treturn channelEventListener;\n\t}\n}\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/production/srv/acceptor/DefaultSrvAcceptor.java",
    "content": "package com.lyncc.netty.production.srv.acceptor;\n\nimport java.net.SocketAddress;\nimport java.util.concurrent.LinkedBlockingQueue;\nimport java.util.concurrent.TimeUnit;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.lyncc.netty.production.common.NettyEvent;\nimport com.lyncc.netty.production.common.ServiceThread;\n\npublic abstract class DefaultSrvAcceptor extends NettySrvAcceptor {\n\t\n\tprivate static final Logger logger = LoggerFactory.getLogger(DefaultCommonSrvAcceptor.class);\n\t\n\tprotected final NettyEventExecuter nettyEventExecuter = new NettyEventExecuter();\n\t\n\tpublic void putNettyEvent(final NettyEvent event) {\n        this.nettyEventExecuter.putNettyEvent(event);\n    }\n\n\tpublic DefaultSrvAcceptor(SocketAddress localAddress) {\n\t\tsuper(localAddress);\n\t}\n\t\n\tclass NettyEventExecuter extends ServiceThread {\n        private final LinkedBlockingQueue<NettyEvent> eventQueue = new LinkedBlockingQueue<NettyEvent>();\n        private final int MaxSize = 10000;\n\n\n        public void putNettyEvent(final NettyEvent event) {\n            if (this.eventQueue.size() <= MaxSize) {\n                this.eventQueue.add(event);\n            }\n            else {\n            \tlogger.warn(\"event queue size[{}] enough, so drop this event {}\", this.eventQueue.size(),\n                    event.toString());\n            }\n        }\n\n        public void run() {\n        \tlogger.info(this.getServiceName() + \" service started\");\n\n            final ChannelEventListener listener = DefaultSrvAcceptor.this.getChannelEventListener();\n\n            while (!this.isStoped()) {\n                try {\n                    NettyEvent event = this.eventQueue.poll(3000, TimeUnit.MILLISECONDS);\n                    if (event != null && listener != null) {\n                        switch (event.getType()) {\n                        case IDLE:\n                            listener.onChannelIdle(event.getRemoteAddr(), event.getChannel());\n                            break;\n                        case CLOSE:\n                            listener.onChannelClose(event.getRemoteAddr(), event.getChannel());\n                            break;\n                        case CONNECT:\n                            listener.onChannelConnect(event.getRemoteAddr(), event.getChannel());\n                            break;\n                        case EXCEPTION:\n                            listener.onChannelException(event.getRemoteAddr(), event.getChannel());\n                            break;\n                        default:\n                            break;\n\n                        }\n                    }\n                }\n                catch (Exception e) {\n                \tlogger.warn(this.getServiceName() + \" service has exception. \", e);\n                }\n            }\n\n            logger.info(this.getServiceName() + \" service end\");\n        }\n\n\n        @Override\n        public String getServiceName() {\n            return NettyEventExecuter.class.getSimpleName();\n        }\n    }\n\n\tprotected abstract ChannelEventListener getChannelEventListener();\n\n}\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/production/srv/acceptor/NettySrvAcceptor.java",
    "content": "package com.lyncc.netty.production.srv.acceptor;\n\nimport io.netty.bootstrap.ServerBootstrap;\nimport io.netty.buffer.ByteBufAllocator;\nimport io.netty.buffer.PooledByteBufAllocator;\nimport io.netty.channel.ChannelFuture;\nimport io.netty.channel.ChannelOption;\nimport io.netty.channel.EventLoopGroup;\nimport io.netty.util.HashedWheelTimer;\nimport io.netty.util.concurrent.DefaultThreadFactory;\nimport io.netty.util.internal.PlatformDependent;\n\nimport java.net.SocketAddress;\nimport java.util.concurrent.ThreadFactory;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * \n * @author BazingaLyn\n * @description Netty Server接收端的{@link ServerBootstrap}的初始化和Netty的一些启动参数\n * @time 2016年7月20日19:56:45\n * @modifytime\n */\npublic abstract class NettySrvAcceptor implements SrvAcceptor {\n\t\n\tprivate static final Logger logger = LoggerFactory.getLogger(NettySrvAcceptor.class);\n\t\n\tpublic static final int AVAILABLE_PROCESSORS = Runtime.getRuntime().availableProcessors();\n\t\n\tprotected final SocketAddress localAddress;\n\t\n\t//netty base element\n\tprivate ServerBootstrap bootstrap;\n    private EventLoopGroup boss;\n    private EventLoopGroup worker;\n    private int nWorkers;\n    protected volatile ByteBufAllocator allocator;\n\t\n\t\n\tprotected final HashedWheelTimer timer = new HashedWheelTimer(new ThreadFactory() {\n\t\t\n\t\tprivate AtomicInteger threadIndex = new AtomicInteger(0);\n\t\t\n\t\tpublic Thread newThread(Runnable runnable) {\n\t\t\treturn new Thread(runnable, \"NettySrvAcceptorExecutor_\" + this.threadIndex.incrementAndGet());\n\t\t}\n\t});\n\t\n\tpublic NettySrvAcceptor(SocketAddress localAddress) {\n        this(localAddress, AVAILABLE_PROCESSORS << 1);\n    }\n\n    public NettySrvAcceptor(SocketAddress localAddress, int nWorkers) {\n        this.localAddress = localAddress;\n        this.nWorkers = nWorkers;\n    }\n    \n    //netty的元素初始化\n    protected void init(){\n    \tThreadFactory bossFactory = new DefaultThreadFactory(\"netty.acceptor.boss\");\n        ThreadFactory workerFactory = new DefaultThreadFactory(\"netty.acceptor.worker\");\n        \n        boss = initEventLoopGroup(1, bossFactory);\n        \n        worker = initEventLoopGroup(nWorkers, workerFactory);\n        //使用池化的directBuffer\n        /**\n         * 一般高性能的场景下,使用的堆外内存，也就是直接内存，使用堆外内存的好处就是减少内存的拷贝，和上下文的切换，缺点是\n         * 堆外内存处理的不好容易发生堆外内存OOM\n         * 当然也要看当前的JVM是否只是使用堆外内存，换而言之就是是否能够获取到Unsafe对象#PlatformDependent.directBufferPreferred()\n         */\n        allocator = new PooledByteBufAllocator(PlatformDependent.directBufferPreferred());\n        //create && group\n        bootstrap= new ServerBootstrap().group(worker, worker);\n        //ByteBufAllocator 配置\n        bootstrap.childOption(ChannelOption.ALLOCATOR, allocator);\n    \t\n    }\n    \n    public void start() throws InterruptedException {\n    \tthis.start(true);\n    }\n    \n    public void start(boolean sync) throws InterruptedException {\n    \tChannelFuture future = bind(localAddress).sync();\n\n        logger.info(\"netty acceptor server start\");\n\n        if (sync) {\n            future.channel().closeFuture().sync();\n        }\n    \t\n    }\n    \n    public SocketAddress localAddress() {\n\t\treturn localAddress;\n\t}\n    \n    protected ServerBootstrap bootstrap() {\n        return bootstrap;\n    }\n    \n\tpublic void shutdownGracefully() {\n    \tboss.shutdownGracefully().awaitUninterruptibly();\n        worker.shutdownGracefully().awaitUninterruptibly();\n    }\n\n\tprotected abstract EventLoopGroup initEventLoopGroup(int nthread, ThreadFactory bossFactory);\n\t\n\tprotected abstract ChannelFuture bind(SocketAddress localAddress);\n\n}\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/production/srv/acceptor/SrvAcceptor.java",
    "content": "package com.lyncc.netty.production.srv.acceptor;\n\nimport java.net.SocketAddress;\n\n/**\n * \n * @author BazingaLyn\n * @description netty server端的标准接口定义\n * @time 2016年7月20日16:41:04\n * @modifytime\n */\npublic interface SrvAcceptor {\n\t\n\tSocketAddress localAddress();\n\t\n\tvoid start() throws InterruptedException;\n\t\n\tvoid shutdownGracefully();\n\t\n\tvoid start(boolean sync) throws InterruptedException;\n\n}\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/production/srv/acceptor/package-info.java",
    "content": "/**\n * @author BazingaLyn\n * netty生成级别的server/client端的模板代码\n * \n * 不一定任何场合都适用，但是自我感觉是一种比较规范的写法\n * \n * 参考 RPC框架 Jupiter https://github.com/fengjiachun/Jupiter\n *    RocketMQ https://github.com/alibaba/RocketMQ\n * @time 2016年7月20日16:06:26\n */\npackage com.lyncc.netty.production.srv.acceptor;"
  },
  {
    "path": "src/main/java/com/lyncc/netty/stickpackage/correct/BaseClient.java",
    "content": "package com.lyncc.netty.stickpackage.correct;\r\n\r\nimport io.netty.bootstrap.Bootstrap;\r\nimport io.netty.channel.ChannelFuture;\r\nimport io.netty.channel.ChannelInitializer;\r\nimport io.netty.channel.ChannelOption;\r\nimport io.netty.channel.ChannelPipeline;\r\nimport io.netty.channel.EventLoopGroup;\r\nimport io.netty.channel.nio.NioEventLoopGroup;\r\nimport io.netty.channel.socket.SocketChannel;\r\nimport io.netty.channel.socket.nio.NioSocketChannel;\r\n\r\npublic class BaseClient {\r\n    \r\n    static final String HOST = System.getProperty(\"host\", \"127.0.0.1\");\r\n    static final int PORT = Integer.parseInt(System.getProperty(\"port\", \"8080\"));\r\n    static final int SIZE = Integer.parseInt(System.getProperty(\"size\", \"256\"));\r\n\r\n    public static void main(String[] args) throws Exception {\r\n\r\n        // Configure the client.\r\n        EventLoopGroup group = new NioEventLoopGroup();\r\n        try {\r\n            Bootstrap b = new Bootstrap();\r\n            b.group(group)\r\n             .channel(NioSocketChannel.class)\r\n             .option(ChannelOption.TCP_NODELAY, true)\r\n             .handler(new ChannelInitializer<SocketChannel>() {\r\n                 @Override\r\n                 public void initChannel(SocketChannel ch) throws Exception {\r\n                     ChannelPipeline p = ch.pipeline();\r\n                     p.addLast(new BaseClientHandler());\r\n                 }\r\n             });\r\n\r\n            ChannelFuture future = b.connect(HOST, PORT).sync();\r\n            future.channel().writeAndFlush(\"Hello Netty Server ,I am a common client\");\r\n            future.channel().closeFuture().sync();\r\n        } finally {\r\n            group.shutdownGracefully();\r\n        }\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/stickpackage/correct/BaseClientHandler.java",
    "content": "package com.lyncc.netty.stickpackage.correct;\r\n\r\nimport io.netty.buffer.ByteBuf;\r\nimport io.netty.buffer.Unpooled;\r\nimport io.netty.channel.ChannelHandlerContext;\r\nimport io.netty.channel.ChannelInboundHandlerAdapter;\r\n\r\n/**\r\n * \r\n * @author bazingaLyncc\r\n * 描述：客户端的第一个自定义的inbound处理器\r\n * 时间  2016年5月3日\r\n */\r\npublic class BaseClientHandler extends ChannelInboundHandlerAdapter{\r\n    \r\n    private byte[] req;\r\n    \r\n    private int counter;\r\n    \r\n    public BaseClientHandler() {\r\n        req = (\"QUERY TIME ORDER\" + System.getProperty(\"line.separator\"))\r\n            .getBytes();\r\n    }\r\n    \r\n    @Override\r\n    public void channelActive(ChannelHandlerContext ctx) throws Exception {\r\n        ByteBuf message = null;\r\n        for (int i = 0; i < 100; i++) {\r\n            message = Unpooled.buffer(req.length);\r\n            message.writeBytes(req);\r\n            ctx.writeAndFlush(message);\r\n        }\r\n    }\r\n    \r\n    @Override\r\n    public void channelRead(ChannelHandlerContext ctx, Object msg)\r\n        throws Exception {\r\n        ByteBuf buf = (ByteBuf) msg;\r\n        byte[] req = new byte[buf.readableBytes()];\r\n        buf.readBytes(req);\r\n        String body = new String(req, \"UTF-8\");\r\n        System.out.println(\"Now is : \" + body + \" ; the counter is : \"+ ++counter);\r\n    }\r\n\r\n    @Override\r\n    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {\r\n        ctx.close();\r\n    }\r\n    \r\n    \r\n\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/stickpackage/correct/BaseServer.java",
    "content": "package com.lyncc.netty.stickpackage.correct;\r\n\r\nimport io.netty.bootstrap.ServerBootstrap;\r\nimport io.netty.channel.ChannelFuture;\r\nimport io.netty.channel.ChannelInitializer;\r\nimport io.netty.channel.ChannelOption;\r\nimport io.netty.channel.EventLoopGroup;\r\nimport io.netty.channel.nio.NioEventLoopGroup;\r\nimport io.netty.channel.socket.SocketChannel;\r\nimport io.netty.channel.socket.nio.NioServerSocketChannel;\r\n\r\nimport java.net.InetSocketAddress;\r\n\r\npublic class BaseServer {\r\n\r\n    private int port;\r\n    \r\n    public BaseServer(int port) {\r\n        this.port = port;\r\n    }\r\n    \r\n    public void start(){\r\n        EventLoopGroup bossGroup = new NioEventLoopGroup(1);\r\n        EventLoopGroup workerGroup = new NioEventLoopGroup();\r\n        try {\r\n            ServerBootstrap sbs = new ServerBootstrap().group(bossGroup,workerGroup).channel(NioServerSocketChannel.class).localAddress(new InetSocketAddress(port))\r\n                    .childHandler(new ChannelInitializer<SocketChannel>() {\r\n                        \r\n                        protected void initChannel(SocketChannel ch) throws Exception {\r\n                            ch.pipeline().addLast(new BaseServerHandler());\r\n                        };\r\n                        \r\n                    }).option(ChannelOption.SO_BACKLOG, 128)   \r\n                    .childOption(ChannelOption.SO_KEEPALIVE, true);\r\n             // 绑定端口，开始接收进来的连接\r\n             ChannelFuture future = sbs.bind(port).sync();  \r\n             \r\n             System.out.println(\"Server start listen at \" + port );\r\n             future.channel().closeFuture().sync();\r\n        } catch (Exception e) {\r\n            bossGroup.shutdownGracefully();\r\n            workerGroup.shutdownGracefully();\r\n        }\r\n    }\r\n    \r\n    public static void main(String[] args) throws Exception {\r\n        int port;\r\n        if (args.length > 0) {\r\n            port = Integer.parseInt(args[0]);\r\n        } else {\r\n            port = 8080;\r\n        }\r\n        new BaseServer(port).start();\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/stickpackage/correct/BaseServerHandler.java",
    "content": "package com.lyncc.netty.stickpackage.correct;\r\n\r\nimport io.netty.buffer.ByteBuf;\r\nimport io.netty.buffer.Unpooled;\r\nimport io.netty.channel.ChannelHandlerContext;\r\nimport io.netty.channel.ChannelInboundHandlerAdapter;\r\nimport io.netty.util.CharsetUtil;\r\n\r\npublic class BaseServerHandler extends ChannelInboundHandlerAdapter{\r\n    \r\n    \r\n    private int counter;\r\n    \r\n    \r\n    @Override\r\n    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {\r\n        \r\n        ByteBuf buf = (ByteBuf)msg;\r\n        byte[] req = new byte[buf.readableBytes()];\r\n        buf.readBytes(req);\r\n        String body = new String(req, CharsetUtil.UTF_8).substring(0, req.length - System.getProperty(\"line.separator\").length());\r\n        System.out.println(\"server receive order : \" + body + \";the counter is: \" + ++counter);\r\n        String currentTime = \"QUERY TIME ORDER\".equalsIgnoreCase(body) ? new java.util.Date(\r\n                System.currentTimeMillis()).toString() : \"BAD ORDER\";\r\n            currentTime = currentTime + System.getProperty(\"line.separator\");\r\n            ByteBuf resp = Unpooled.copiedBuffer(currentTime.getBytes());\r\n            ctx.writeAndFlush(resp);\r\n    }\r\n    \r\n    \r\n    @Override\r\n    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {\r\n        cause.printStackTrace();\r\n        ctx.close();\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/stickpackage/delimiter/BaseClient.java",
    "content": "package com.lyncc.netty.stickpackage.delimiter;\r\n\r\nimport io.netty.bootstrap.Bootstrap;\r\nimport io.netty.buffer.ByteBuf;\r\nimport io.netty.buffer.Unpooled;\r\nimport io.netty.channel.ChannelFuture;\r\nimport io.netty.channel.ChannelInitializer;\r\nimport io.netty.channel.ChannelOption;\r\nimport io.netty.channel.ChannelPipeline;\r\nimport io.netty.channel.EventLoopGroup;\r\nimport io.netty.channel.nio.NioEventLoopGroup;\r\nimport io.netty.channel.socket.SocketChannel;\r\nimport io.netty.channel.socket.nio.NioSocketChannel;\r\nimport io.netty.handler.codec.DelimiterBasedFrameDecoder;\r\nimport io.netty.handler.codec.string.StringDecoder;\r\n\r\npublic class BaseClient {\r\n    \r\n    static final String HOST = System.getProperty(\"host\", \"127.0.0.1\");\r\n    static final int PORT = Integer.parseInt(System.getProperty(\"port\", \"8080\"));\r\n    static final int SIZE = Integer.parseInt(System.getProperty(\"size\", \"256\"));\r\n\r\n    public static void main(String[] args) throws Exception {\r\n\r\n        // Configure the client.\r\n        EventLoopGroup group = new NioEventLoopGroup();\r\n        try {\r\n            Bootstrap b = new Bootstrap();\r\n            b.group(group)\r\n             .channel(NioSocketChannel.class)\r\n             .option(ChannelOption.TCP_NODELAY, true)\r\n             .handler(new ChannelInitializer<SocketChannel>() {\r\n                 @Override\r\n                 public void initChannel(SocketChannel ch) throws Exception {\r\n                     \r\n                     ByteBuf delimiter = Unpooled.copiedBuffer(\"$_\".getBytes());\r\n                     ChannelPipeline p = ch.pipeline();\r\n                     \r\n                     p.addLast(new DelimiterBasedFrameDecoder(1024,delimiter));\r\n                     p.addLast(new StringDecoder());\r\n                     p.addLast(new BaseClientHandler());\r\n                 }\r\n             });\r\n\r\n            ChannelFuture future = b.connect(HOST, PORT).sync();\r\n            future.channel().writeAndFlush(\"Hello Netty Server ,I am a common client\");\r\n            future.channel().closeFuture().sync();\r\n        } finally {\r\n            group.shutdownGracefully();\r\n        }\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/stickpackage/delimiter/BaseClientHandler.java",
    "content": "package com.lyncc.netty.stickpackage.delimiter;\r\n\r\nimport io.netty.buffer.Unpooled;\r\nimport io.netty.channel.ChannelHandlerContext;\r\nimport io.netty.channel.ChannelInboundHandlerAdapter;\r\n\r\n/**\r\n * \r\n * @author bazingaLyncc\r\n * 描述：客户端的第一个自定义的inbound处理器\r\n * 时间  2016年5月3日\r\n */\r\npublic class BaseClientHandler extends ChannelInboundHandlerAdapter{\r\n    \r\n    private int counter;\r\n    \r\n    static final String FIXED_REQ = \"Hi,Lyncc,Learn English.$_\";\r\n    \r\n    @Override\r\n    public void channelActive(ChannelHandlerContext ctx) throws Exception {\r\n        for (int i = 0; i < 100; i++) {\r\n            ctx.writeAndFlush(Unpooled.copiedBuffer(FIXED_REQ.getBytes()));\r\n        }\r\n    }\r\n    \r\n    @Override\r\n    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {\r\n        \r\n        System.out.println(\"Now is : \" + msg + \" ; the counter is : \"+ ++counter);\r\n    }\r\n\r\n    @Override\r\n    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {\r\n        ctx.close();\r\n    }\r\n    \r\n    \r\n\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/stickpackage/delimiter/BaseServer.java",
    "content": "package com.lyncc.netty.stickpackage.delimiter;\r\n\r\nimport io.netty.bootstrap.ServerBootstrap;\r\nimport io.netty.buffer.ByteBuf;\r\nimport io.netty.buffer.Unpooled;\r\nimport io.netty.channel.ChannelFuture;\r\nimport io.netty.channel.ChannelInitializer;\r\nimport io.netty.channel.ChannelOption;\r\nimport io.netty.channel.ChannelPipeline;\r\nimport io.netty.channel.EventLoopGroup;\r\nimport io.netty.channel.nio.NioEventLoopGroup;\r\nimport io.netty.channel.socket.SocketChannel;\r\nimport io.netty.channel.socket.nio.NioServerSocketChannel;\r\nimport io.netty.handler.codec.DelimiterBasedFrameDecoder;\r\nimport io.netty.handler.codec.string.StringDecoder;\r\n\r\nimport java.net.InetSocketAddress;\r\n\r\npublic class BaseServer {\r\n\r\n    private int port;\r\n    \r\n    public BaseServer(int port) {\r\n        this.port = port;\r\n    }\r\n    \r\n    public void start(){\r\n        EventLoopGroup bossGroup = new NioEventLoopGroup(1);\r\n        EventLoopGroup workerGroup = new NioEventLoopGroup();\r\n        try {\r\n            ServerBootstrap sbs = new ServerBootstrap().group(bossGroup,workerGroup).channel(NioServerSocketChannel.class).localAddress(new InetSocketAddress(port))\r\n                    .childHandler(new ChannelInitializer<SocketChannel>() {\r\n                        \r\n                        protected void initChannel(SocketChannel ch) throws Exception {\r\n                            \r\n                            ByteBuf delimiter = Unpooled.copiedBuffer(\"$_\".getBytes());\r\n                            ChannelPipeline p = ch.pipeline();\r\n                            \r\n                            p.addLast(new DelimiterBasedFrameDecoder(1024,delimiter));\r\n                            p.addLast(new StringDecoder());\r\n                            \r\n                            p.addLast(new BaseServerHandler());\r\n                        };\r\n                        \r\n                    }).option(ChannelOption.SO_BACKLOG, 128)   \r\n                    .childOption(ChannelOption.SO_KEEPALIVE, true);\r\n             // 绑定端口，开始接收进来的连接\r\n             ChannelFuture future = sbs.bind(port).sync();  \r\n             \r\n             System.out.println(\"Server start listen at \" + port );\r\n             future.channel().closeFuture().sync();\r\n        } catch (Exception e) {\r\n            bossGroup.shutdownGracefully();\r\n            workerGroup.shutdownGracefully();\r\n        }\r\n    }\r\n    \r\n    public static void main(String[] args) throws Exception {\r\n        int port;\r\n        if (args.length > 0) {\r\n            port = Integer.parseInt(args[0]);\r\n        } else {\r\n            port = 8080;\r\n        }\r\n        new BaseServer(port).start();\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/stickpackage/delimiter/BaseServerHandler.java",
    "content": "package com.lyncc.netty.stickpackage.delimiter;\r\n\r\nimport io.netty.channel.ChannelHandlerContext;\r\nimport io.netty.channel.ChannelInboundHandlerAdapter;\r\n\r\npublic class BaseServerHandler extends ChannelInboundHandlerAdapter{\r\n    \r\n    \r\n    private int counter;\r\n    \r\n    \r\n    @Override\r\n    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {\r\n        System.out.println(msg + \" the counter is \" + ++counter);\r\n         \r\n    }\r\n    \r\n    \r\n    @Override\r\n    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {\r\n        cause.printStackTrace();\r\n        ctx.close();\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/stickpackage/error/BaseClient.java",
    "content": "package com.lyncc.netty.stickpackage.error;\r\n\r\nimport io.netty.bootstrap.Bootstrap;\r\nimport io.netty.channel.ChannelFuture;\r\nimport io.netty.channel.ChannelInitializer;\r\nimport io.netty.channel.ChannelOption;\r\nimport io.netty.channel.ChannelPipeline;\r\nimport io.netty.channel.EventLoopGroup;\r\nimport io.netty.channel.nio.NioEventLoopGroup;\r\nimport io.netty.channel.socket.SocketChannel;\r\nimport io.netty.channel.socket.nio.NioSocketChannel;\r\nimport io.netty.handler.codec.LineBasedFrameDecoder;\r\nimport io.netty.handler.codec.string.StringDecoder;\r\n\r\npublic class BaseClient {\r\n    \r\n    static final String HOST = System.getProperty(\"host\", \"127.0.0.1\");\r\n    static final int PORT = Integer.parseInt(System.getProperty(\"port\", \"8080\"));\r\n    static final int SIZE = Integer.parseInt(System.getProperty(\"size\", \"256\"));\r\n\r\n    public static void main(String[] args) throws Exception {\r\n\r\n        // Configure the client.\r\n        EventLoopGroup group = new NioEventLoopGroup();\r\n        try {\r\n            Bootstrap b = new Bootstrap();\r\n            b.group(group)\r\n             .channel(NioSocketChannel.class)\r\n             .option(ChannelOption.TCP_NODELAY, true)\r\n             .handler(new ChannelInitializer<SocketChannel>() {\r\n                 @Override\r\n                 public void initChannel(SocketChannel ch) throws Exception {\r\n                     ChannelPipeline p = ch.pipeline();\r\n                     p.addLast(new LineBasedFrameDecoder(1024));\r\n                     p.addLast(new StringDecoder());\r\n                     p.addLast(new BaseClientHandler());\r\n                 }\r\n             });\r\n\r\n            ChannelFuture future = b.connect(HOST, PORT).sync();\r\n            future.channel().writeAndFlush(\"Hello Netty Server ,I am a common client\");\r\n            future.channel().closeFuture().sync();\r\n        } finally {\r\n            group.shutdownGracefully();\r\n        }\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/stickpackage/error/BaseClientHandler.java",
    "content": "package com.lyncc.netty.stickpackage.error;\r\n\r\nimport io.netty.buffer.ByteBuf;\r\nimport io.netty.buffer.Unpooled;\r\nimport io.netty.channel.ChannelHandlerContext;\r\nimport io.netty.channel.ChannelInboundHandlerAdapter;\r\n\r\n/**\r\n * \r\n * @author bazingaLyncc\r\n * 描述：客户端的第一个自定义的inbound处理器\r\n * 时间  2016年5月3日\r\n */\r\npublic class BaseClientHandler extends ChannelInboundHandlerAdapter{\r\n    \r\n    private byte[] req;\r\n    \r\n    private int counter;\r\n    \r\n    public BaseClientHandler() {\r\n        req = (\"QUERY TIME ORDER\" + System.getProperty(\"line.separator\"))\r\n            .getBytes();\r\n    }\r\n    \r\n    @Override\r\n    public void channelActive(ChannelHandlerContext ctx) throws Exception {\r\n        ByteBuf message = null;\r\n        for (int i = 0; i < 100; i++) {\r\n            message = Unpooled.buffer(req.length);\r\n            message.writeBytes(req);\r\n            ctx.writeAndFlush(message);\r\n        }\r\n    }\r\n    \r\n    @Override\r\n    public void channelRead(ChannelHandlerContext ctx, Object msg)\r\n        throws Exception {\r\n        String buf = (String) msg;\r\n        System.out.println(\"Now is : \" + buf + \" ; the counter is : \"+ ++counter);\r\n    }\r\n\r\n    @Override\r\n    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {\r\n        ctx.close();\r\n    }\r\n    \r\n    \r\n\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/stickpackage/error/BaseServer.java",
    "content": "package com.lyncc.netty.stickpackage.error;\r\n\r\nimport io.netty.bootstrap.ServerBootstrap;\r\nimport io.netty.channel.ChannelFuture;\r\nimport io.netty.channel.ChannelInitializer;\r\nimport io.netty.channel.ChannelOption;\r\nimport io.netty.channel.EventLoopGroup;\r\nimport io.netty.channel.nio.NioEventLoopGroup;\r\nimport io.netty.channel.socket.SocketChannel;\r\nimport io.netty.channel.socket.nio.NioServerSocketChannel;\r\nimport io.netty.handler.codec.LineBasedFrameDecoder;\r\nimport io.netty.handler.codec.string.StringDecoder;\r\n\r\nimport java.net.InetSocketAddress;\r\n\r\npublic class BaseServer {\r\n\r\n    private int port;\r\n    \r\n    public BaseServer(int port) {\r\n        this.port = port;\r\n    }\r\n    \r\n    public void start(){\r\n        EventLoopGroup bossGroup = new NioEventLoopGroup(1);\r\n        EventLoopGroup workerGroup = new NioEventLoopGroup();\r\n        try {\r\n            ServerBootstrap sbs = new ServerBootstrap().group(bossGroup,workerGroup).channel(NioServerSocketChannel.class).localAddress(new InetSocketAddress(port))\r\n                    .childHandler(new ChannelInitializer<SocketChannel>() {\r\n                        \r\n                        protected void initChannel(SocketChannel ch) throws Exception {\r\n                            ch.pipeline().addLast(new LineBasedFrameDecoder(1024));\r\n                            ch.pipeline().addLast(new StringDecoder());\r\n                            ch.pipeline().addLast(new BaseServerHandler());\r\n                        };\r\n                        \r\n                    }).option(ChannelOption.SO_BACKLOG, 128)   \r\n                    .childOption(ChannelOption.SO_KEEPALIVE, true);\r\n             // 绑定端口，开始接收进来的连接\r\n             ChannelFuture future = sbs.bind(port).sync();  \r\n             \r\n             System.out.println(\"Server start listen at \" + port );\r\n             future.channel().closeFuture().sync();\r\n        } catch (Exception e) {\r\n            bossGroup.shutdownGracefully();\r\n            workerGroup.shutdownGracefully();\r\n        }\r\n    }\r\n    \r\n    public static void main(String[] args) throws Exception {\r\n        int port;\r\n        if (args.length > 0) {\r\n            port = Integer.parseInt(args[0]);\r\n        } else {\r\n            port = 8080;\r\n        }\r\n        new BaseServer(port).start();\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/stickpackage/error/BaseServerHandler.java",
    "content": "package com.lyncc.netty.stickpackage.error;\r\n\r\nimport io.netty.buffer.ByteBuf;\r\nimport io.netty.buffer.Unpooled;\r\nimport io.netty.channel.ChannelHandlerContext;\r\nimport io.netty.channel.ChannelInboundHandlerAdapter;\r\n\r\npublic class BaseServerHandler extends ChannelInboundHandlerAdapter{\r\n    \r\n    \r\n    private int counter;\r\n    \r\n    \r\n    @Override\r\n    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {\r\n        \r\n        String body = (String)msg;\r\n        System.out.println(\"server receive order : \" + body + \";the counter is: \" + ++counter);\r\n        String currentTime = \"QUERY TIME ORDER\".equalsIgnoreCase(body) ? new java.util.Date(\r\n                System.currentTimeMillis()).toString() : \"BAD ORDER\";\r\n            currentTime = currentTime + System.getProperty(\"line.separator\");\r\n            ByteBuf resp = Unpooled.copiedBuffer(currentTime.getBytes());\r\n            ctx.writeAndFlush(resp);\r\n    }\r\n    \r\n    \r\n    @Override\r\n    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {\r\n        cause.printStackTrace();\r\n        ctx.close();\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/stickpackage/myself/BaseClient.java",
    "content": "package com.lyncc.netty.stickpackage.myself;\r\n\r\nimport io.netty.bootstrap.Bootstrap;\r\nimport io.netty.channel.ChannelFuture;\r\nimport io.netty.channel.ChannelInitializer;\r\nimport io.netty.channel.ChannelOption;\r\nimport io.netty.channel.ChannelPipeline;\r\nimport io.netty.channel.EventLoopGroup;\r\nimport io.netty.channel.nio.NioEventLoopGroup;\r\nimport io.netty.channel.socket.SocketChannel;\r\nimport io.netty.channel.socket.nio.NioSocketChannel;\r\nimport io.netty.handler.codec.string.StringDecoder;\r\n\r\npublic class BaseClient {\r\n    \r\n    static final String HOST = System.getProperty(\"host\", \"127.0.0.1\");\r\n    static final int PORT = Integer.parseInt(System.getProperty(\"port\", \"8080\"));\r\n    static final int SIZE = Integer.parseInt(System.getProperty(\"size\", \"256\"));\r\n\r\n    public static void main(String[] args) throws Exception {\r\n\r\n        EventLoopGroup group = new NioEventLoopGroup();\r\n        try {\r\n            Bootstrap b = new Bootstrap();\r\n            b.group(group)\r\n             .channel(NioSocketChannel.class)\r\n             .option(ChannelOption.TCP_NODELAY,true)\r\n             .handler(new ChannelInitializer<SocketChannel>() {\r\n                 @Override\r\n                 public void initChannel(SocketChannel ch) throws Exception {\r\n                     ChannelPipeline p = ch.pipeline();\r\n//                     p.addLast(new LineBasedFrameDecoder(1024));\r\n                     p.addLast(new StringDecoder());\r\n                     p.addLast(new BaseClientHandler());\r\n                 }\r\n             });\r\n\r\n            ChannelFuture future = b.connect(HOST, PORT).sync();\r\n            future.channel().writeAndFlush(\"Hello Netty Server ,I am a common client\");\r\n            future.channel().closeFuture().sync();\r\n        } finally {\r\n            group.shutdownGracefully();\r\n        }\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/stickpackage/myself/BaseClientHandler.java",
    "content": "package com.lyncc.netty.stickpackage.myself;\r\n\r\nimport io.netty.buffer.ByteBuf;\r\nimport io.netty.buffer.Unpooled;\r\nimport io.netty.channel.ChannelHandlerContext;\r\nimport io.netty.channel.ChannelInboundHandlerAdapter;\r\n\r\npublic class BaseClientHandler extends ChannelInboundHandlerAdapter{\r\n    \r\n    private byte[] req;\r\n    \r\n    public BaseClientHandler() {\r\n//        req = (\"BazingaLyncc is learner\").getBytes();\r\n        req = (\"In this chapter you general, we recommend Java Concurrency in Practice by Brian Goetz. $$__ His book w\"\r\n                + \"ill give We’ve reached an exciting point—in the next chapter we’ll $$__ discuss bootstrapping, the process \"\r\n                + \"of configuring and connecting all of Netty’s components to bring $$__ your learned about threading models in ge\"\r\n                + \"neral and Netty’s threading model in particular, whose performance $$__ and consistency advantages we discuss\"\r\n                + \"ed in detail In this chapter you general, we recommend Java  $$__Concurrency in Practice by Brian Goetz. Hi\"\r\n                + \"s book will give We’ve reached an exciting point—in the next $$__ chapter we’ll discuss bootstrapping, the\"\r\n                + \" process of configuring and connecting all of Netty’s components $$__ to bring your learned about threading \"\r\n                + \"models in general and Netty’s threading model in particular, $$__ whose performance and consistency advantag\"\r\n                + \"es we discussed in detailIn this chapter you general, $$__ we recommend Java Concurrency in Practice by Bri\"\r\n                + \"an Goetz. His book will give We’ve reached an exciting $$__ point—in the next chapter;the counter is: 1 2222\"\r\n                + \"sdsa ddasd asdsadas dsadasdas\" + System.getProperty(\"line.separator\")).getBytes();\r\n    }\r\n    \r\n    \r\n    @Override\r\n    public void channelActive(ChannelHandlerContext ctx) throws Exception {\r\n        ByteBuf message = null;\r\n//        for (int i = 0; i < 100; i++) {\r\n//            message = Unpooled.buffer(req.length);\r\n//            message.writeBytes(req);\r\n//            ctx.writeAndFlush(message);\r\n//        }\r\n        message = Unpooled.buffer(req.length);\r\n        message.writeBytes(req);\r\n        ctx.writeAndFlush(message);\r\n        message = Unpooled.buffer(req.length);\r\n        message.writeBytes(req);\r\n        ctx.writeAndFlush(message);\r\n        \r\n    }\r\n\r\n    @Override\r\n    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {\r\n        ctx.close();\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/stickpackage/myself/BaseServer.java",
    "content": "package com.lyncc.netty.stickpackage.myself;\r\n\r\nimport io.netty.bootstrap.ServerBootstrap;\r\nimport io.netty.buffer.Unpooled;\r\nimport io.netty.channel.ChannelFuture;\r\nimport io.netty.channel.ChannelInitializer;\r\nimport io.netty.channel.ChannelOption;\r\nimport io.netty.channel.EventLoopGroup;\r\nimport io.netty.channel.nio.NioEventLoopGroup;\r\nimport io.netty.channel.socket.SocketChannel;\r\nimport io.netty.channel.socket.nio.NioServerSocketChannel;\r\nimport io.netty.handler.codec.DelimiterBasedFrameDecoder;\r\nimport io.netty.handler.codec.FixedLengthFrameDecoder;\r\nimport io.netty.handler.codec.string.StringDecoder;\r\n\r\nimport java.net.InetSocketAddress;\r\n\r\npublic class BaseServer {\r\n\r\n    private int port;\r\n    \r\n    public BaseServer(int port) {\r\n        this.port = port;\r\n    }\r\n    \r\n    public void start(){\r\n        EventLoopGroup bossGroup = new NioEventLoopGroup(1);\r\n        EventLoopGroup workerGroup = new NioEventLoopGroup();\r\n        try {\r\n            ServerBootstrap sbs = new ServerBootstrap().group(bossGroup,workerGroup).channel(NioServerSocketChannel.class).localAddress(new InetSocketAddress(port))\r\n                    .childHandler(new ChannelInitializer<SocketChannel>() {\r\n                        \r\n                        protected void initChannel(SocketChannel ch) throws Exception {\r\n                            ch.pipeline().addLast(new DelimiterBasedFrameDecoder(1024,Unpooled.copiedBuffer(\"$$__\".getBytes())));\r\n                            ch.pipeline().addLast(new StringDecoder());\r\n                            ch.pipeline().addLast(new BaseServerHandler());\r\n                        };\r\n                        \r\n                    }).option(ChannelOption.SO_BACKLOG, 128)   \r\n                    .childOption(ChannelOption.SO_KEEPALIVE, true);\r\n             // 绑定端口，开始接收进来的连接\r\n             ChannelFuture future = sbs.bind(port).sync();  \r\n             \r\n             System.out.println(\"Server start listen at \" + port );\r\n             future.channel().closeFuture().sync();\r\n        } catch (Exception e) {\r\n            bossGroup.shutdownGracefully();\r\n            workerGroup.shutdownGracefully();\r\n        }\r\n    }\r\n    \r\n    public static void main(String[] args) throws Exception {\r\n        int port;\r\n        if (args.length > 0) {\r\n            port = Integer.parseInt(args[0]);\r\n        } else {\r\n            port = 8080;\r\n        }\r\n        new BaseServer(port).start();\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/lyncc/netty/stickpackage/myself/BaseServerHandler.java",
    "content": "package com.lyncc.netty.stickpackage.myself;\r\n\r\nimport io.netty.channel.ChannelHandlerContext;\r\nimport io.netty.channel.ChannelInboundHandlerAdapter;\r\n\r\npublic class BaseServerHandler extends ChannelInboundHandlerAdapter{\r\n    \r\n    \r\n    private int counter;\r\n    \r\n    \r\n    @Override\r\n    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {\r\n        \r\n        String body = (String)msg;\r\n        System.out.println(\"server receive order : \" + body + \";the counter is: \" + ++counter);\r\n    }\r\n    \r\n    \r\n    @Override\r\n    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {\r\n        cause.printStackTrace();\r\n        ctx.close();\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "src/main/resources/logback.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n\n<!--\n  ~ Copyright (c) 2015 The Jupiter Project\n  ~\n  ~ Licensed under the Apache License, version 2.0 (the \"License\");\n  ~ you may not use this file except in compliance with the License.\n  ~ You may obtain a copy of the License at:\n  ~\n  ~   http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~ Unless required by applicable law or agreed to in writing, software\n  ~ distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~ See the License for the specific language governing permissions and\n  ~ limitations under the License.\n  -->\n\n<configuration scan=\"false\">\n    <!-- 标准输出 -->\n    <appender name=\"STD_OUT\" class=\"ch.qos.logback.core.ConsoleAppender\">\n        <layout class=\"ch.qos.logback.classic.PatternLayout\">\n            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level [%thread] [%logger{0}] - %msg%n</pattern>\n        </layout>\n    </appender>\n\n    <!--<appender name=\"FILE_OUT\" class=\"ch.qos.logback.core.FileAppender\">-->\n        <!--<File>logs/log.log</File>-->\n        <!--<layout class=\"ch.qos.logback.classic.PatternLayout\">-->\n            <!--<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level [%thread] [%logger{0}] - %msg%n</pattern>-->\n        <!--</layout>-->\n    <!--</appender>-->\n\n    <appender name=\"ASYNC_OUT\" class=\"ch.qos.logback.classic.AsyncAppender\">\n        <!-- 如果队列元素超过容量80%，丢掉WARN级别以下的新日志 -->\n        <queueSize>65536</queueSize>\n        <appender-ref ref=\"STD_OUT\" />\n    </appender>\n\n    <root level=\"INFO\">\n        <appender-ref ref=\"ASYNC_OUT\" />\n    </root>\n</configuration>"
  }
]