读书笔记-Netty的分隔符和定长解码器

TCP以流的方式进行数据传输,上层的应用协议为了对消息进行分区,往往采用下面4种方式:

(1)消息长度固定,累计读取到长度总和为定长LEN的报文后,就以为读取到了一个完整的消息;将计数器置位,重新开始读取下一个数据报;

(2)将回车换行符作为消息结束符,例如FTP协议,这种方式在文本协议中应用比较广泛;

(3)将特殊的分隔符作为消息的结束标志,回车换行符就是一种特殊的结束分隔符;

(4)通过在消息头中定义长度字段来标识消息的总长度。

我们先来看看通过DelimiterBasedFrameDecoder的使用,我们可以自动完成以分隔符作为码流结束标识的消息的解码;通过一个实例来演示,EchoServer接受到EchoClient的请求 消息后,将其打印出来,然后将原始消息返回给客户端,消息以”$_”作为分隔符。

1.EchoServer.java


import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;

/**
 * @author
 * @Description:
 * @Date: Created in 10:47 2018/7/2
 * @Modified By:
 */
public class EchoServer {



    public static void main(String[] args) throws Exception {
        int port = 9090;
        if (args != null && args.length > 0) {

            try {
                port = Integer.valueOf(args[0]);
            } catch (NumberFormatException e) {
                e.printStackTrace();
            }
        }

        new EchoServer().bind(port);
    }

    public void bind(int port) throws Exception{

        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();

        try {

            ServerBootstrap bootstrap = new ServerBootstrap();

            bootstrap.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG, 1024)
                    .handler(new LoggingHandler(LogLevel.INFO))
                    .childHandler(new ChannelInitializer<SocketChannel>(){

                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ByteBuf delimeter = Unpooled.copiedBuffer("$_".getBytes());
                            ch.pipeline().addLast(new DelimiterBasedFrameDecoder(1024,delimeter));
                            ch.pipeline().addLast(new StringDecoder());

                            ch.pipeline().addLast(new EchoServerHandler());
                        }
                    });

            ChannelFuture future = bootstrap.bind(port).sync();

            future.channel().closeFuture().sync();
        } catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        }finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}

2.EchoServerHandler.java


import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;

/**
 * @author ${user}
 * @Description:
 * @Date: Created in 10:51 2018/7/2
 * @Modified By:
 */
public class EchoServerHandler extends ChannelHandlerAdapter{


    int counter = 0;

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {

        cause.printStackTrace();
        ctx.close();
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {

        String body = (String) msg;

        System.out.println("this is "+ (++counter) + " times receive client : [ "+body+" ]");

        body += "----------------------------.$_";
        //System.out.println("body : "+body);
        ByteBuf echo = Unpooled.copiedBuffer(body.getBytes());
        ctx.writeAndFlush(echo);

    }


}

3.EchoClient.java

import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;

/**
 * @author ${user}
 * @Description:
 * @Date: Created in 10:53 2018/7/2
 * @Modified By:
 */
public class EchoClient {

    public void connect(int port,String host) throws Exception{
        //配置客户端NIO线程组
        EventLoopGroup group = new NioEventLoopGroup();
        try{
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(group).channel(NioSocketChannel.class)
                    .option(ChannelOption.TCP_NODELAY,true)
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ByteBuf delimiter = Unpooled.copiedBuffer("$_".getBytes());

                            ch.pipeline().addLast(new DelimiterBasedFrameDecoder(1024,delimiter));
                            ch.pipeline().addLast(new StringDecoder());
                            ch.pipeline().addLast(new EchoClientHandler());
                        }
                    });

            ChannelFuture future = bootstrap.connect(host,port).sync();

            future.channel().closeFuture().sync();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            group.shutdownGracefully();
        }

    }

    public static void main(String[] args) throws Exception {
        int port = 9090;
        if (args != null && args.length > 0) {

            try {
                port = Integer.valueOf(args[0]);
            } catch (NumberFormatException e) {
                e.printStackTrace();
            }
        }

        new EchoClient().connect(port,"127.0.0.1");
    }

}

4.EchoClientHandler.java

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;

/**
 * @author ${user}
 * @Description:
 * @Date: Created in 11:03 2018/7/2
 * @Modified By:
 */
public class EchoClientHandler extends ChannelHandlerAdapter {

    private int counter;

    static final String ECHO_REQ = "Hi, i am client,welcome to netty.$_";

    public EchoClientHandler(){

    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {

        for (int i=0;i<10;i++){
            ByteBuf buf = Unpooled.copiedBuffer(ECHO_REQ.getBytes());
            ctx.writeAndFlush(buf);
        }
    }


    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        String body = (String) msg;

        System.out.println("Now is : "+ body+"; the counter is : "+(++counter));
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {

        ctx.flush();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.close();
    }
}

测试结果:
1.服务端控制台结果

七月 02, 2018 11:16:02 上午 io.netty.handler.logging.LoggingHandler channelRegistered
信息: [id: 0x09cd5cfd] REGISTERED
七月 02, 2018 11:16:02 上午 io.netty.handler.logging.LoggingHandler bind
信息: [id: 0x09cd5cfd] BIND: 0.0.0.0/0.0.0.0:9090
七月 02, 2018 11:16:02 上午 io.netty.handler.logging.LoggingHandler channelActive
信息: [id: 0x09cd5cfd, /0:0:0:0:0:0:0:0:9090] ACTIVE
七月 02, 2018 11:16:05 上午 io.netty.handler.logging.LoggingHandler channelRead
信息: [id: 0x09cd5cfd, /0:0:0:0:0:0:0:0:9090] RECEIVED: [id: 0xda9d9898, /127.0.0.1:51862 => /127.0.0.1:9090]
this is 1 times receive client : [ Hi, i am client,welcome to netty. ]
this is 2 times receive client : [ Hi, i am client,welcome to netty. ]
this is 3 times receive client : [ Hi, i am client,welcome to netty. ]
this is 4 times receive client : [ Hi, i am client,welcome to netty. ]
this is 5 times receive client : [ Hi, i am client,welcome to netty. ]
this is 6 times receive client : [ Hi, i am client,welcome to netty. ]
this is 7 times receive client : [ Hi, i am client,welcome to netty. ]
this is 8 times receive client : [ Hi, i am client,welcome to netty. ]
this is 9 times receive client : [ Hi, i am client,welcome to netty. ]
this is 10 times receive client : [ Hi, i am client,welcome to netty. ]

2.客户端控制台

Now is : Hi, i am client,welcome to netty.—————————-.; the counter is : 1
Now is : Hi, i am client,welcome to netty.—————————-.; the counter is : 2
Now is : Hi, i am client,welcome to netty.—————————-.; the counter is : 3
Now is : Hi, i am client,welcome to netty.—————————-.; the counter is : 4
Now is : Hi, i am client,welcome to netty.—————————-.; the counter is : 5
Now is : Hi, i am client,welcome to netty.—————————-.; the counter is : 6
Now is : Hi, i am client,welcome to netty.—————————-.; the counter is : 7
Now is : Hi, i am client,welcome to netty.—————————-.; the counter is : 8
Now is : Hi, i am client,welcome to netty.—————————-.; the counter is : 9
Now is : Hi, i am client,welcome to netty.—————————-.; the counter is : 10

猜你喜欢

转载自blog.csdn.net/guo20082200/article/details/80881994