Netty 粘包、拆包解决示例

来源:互联网 发布:英国gpa标准加权算法 编辑:程序博客网 时间:2024/05/17 20:49

Netty是一个高性能、异步事件驱动的NIO框架,它提供了对TCP、UDP和文件传输的支持,作为一个异步NIO框架,Netty的所有IO操作都是异步非阻塞的,通过Future-Listener机制,用户可以方便的主动获取或者通过通知机制获得IO操作结果。

作为当前最流行的NIO框架,Netty在互联网领域、大数据分布式计算领域、游戏行业、通信行业等获得了广泛的应用,一些业界著名的开源组件也基于Netty的NIO框架构建。


Netty示例

public class NettyServer {    public void bind(int port) throws Exception {        // 配置服务端的NIO线程组        EventLoopGroup bossGroup = new NioEventLoopGroup();        EventLoopGroup workerGroup = new NioEventLoopGroup();        try {            ServerBootstrap b = new ServerBootstrap();            b.group(bossGroup, workerGroup)                    .channel(NioServerSocketChannel.class)                    .option(ChannelOption.SO_BACKLOG, 1024)                    .childHandler(new ChannelInitializer<SocketChannel>() {                        @Override                        protected void initChannel(SocketChannel ch) throws Exception {                            ch.pipeline().addLast(new NettyServerHandler());                        }                    });            // 绑定端口,同步等待成功            ChannelFuture f = b.bind(port).sync();            // 等待服务端监听端口关闭            f.channel().closeFuture().sync();        } finally {            // 优雅退出,释放线程池资源            bossGroup.shutdownGracefully();            workerGroup.shutdownGracefully();        }    }    /**     * @param args     * @throws Exception     */    public static void main(String[] args) throws Exception {        int port = 8080;        new NettyServer().bind(port);    }}
public class NettyServerHandler extends ChannelHandlerAdapter {    @Override    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {        ByteBuf buf = (ByteBuf) msg;        byte[] req = new byte[buf.readableBytes()];        buf.readBytes(req);        String body = new String(req, "UTF-8");        System.out.println("The time server receive order : " + body);        String currentTime = "heqing".equalsIgnoreCase(body) ? new java.util.Date(                System.currentTimeMillis()).toString() : "BAD ORDER";        ByteBuf resp = Unpooled.copiedBuffer(currentTime.getBytes());        ctx.write(resp);    }    @Override    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {        ctx.flush();    }    @Override    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {        ctx.close();    }}
public class NettyClient {    public void connect(int port, String host) throws Exception {        // 配置客户端NIO线程组        EventLoopGroup group = new NioEventLoopGroup();        try {            Bootstrap b = new Bootstrap();            b.group(group).channel(NioSocketChannel.class)                    .option(ChannelOption.TCP_NODELAY, true)                    .handler(new ChannelInitializer<SocketChannel>() {                        @Override                        public void initChannel(SocketChannel ch) throws Exception {                            ch.pipeline().addLast(new NettyClientHandler());                        }                    });            // 发起异步连接操作            ChannelFuture f = b.connect(host, port).sync();            // 当代客户端链路关闭            f.channel().closeFuture().sync();        } finally {            // 优雅退出,释放NIO线程组            group.shutdownGracefully();        }    }    /**     * @param args     * @throws Exception     */    public static void main(String[] args) throws Exception {        int port = 8080;        new NettyClient().connect(port, "127.0.0.1");    }}
public class NettyClientHandler extends ChannelHandlerAdapter {    private static final Logger logger = Logger.getLogger(NettyClientHandler.class.getName());    private final ByteBuf firstMessage;    /**     * Creates a client-side handler.     */    public NettyClientHandler() {        byte[] req = "heqing".getBytes();        firstMessage = Unpooled.buffer(req.length);        firstMessage.writeBytes(req);    }    @Override    public void channelActive(ChannelHandlerContext ctx) {        ctx.writeAndFlush(firstMessage);    }    @Override    public void channelRead(ChannelHandlerContext ctx, Object msg)            throws Exception {        ByteBuf buf = (ByteBuf) msg;        byte[] req = new byte[buf.readableBytes()];        buf.readBytes(req);        String body = new String(req, "UTF-8");        System.out.println("Now is : " + body);    }    @Override    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {        // 释放资源        logger.warning("Unexpected exception from downstream : "+ cause.getMessage());        ctx.close();    }}

粘包、拆包

public class PacketServer {    public void bind(int port) throws Exception {        // 配置服务端的NIO线程组        EventLoopGroup bossGroup = new NioEventLoopGroup();        EventLoopGroup workerGroup = new NioEventLoopGroup();        try {            ServerBootstrap b = new ServerBootstrap();            b.group(bossGroup, workerGroup)                    .channel(NioServerSocketChannel.class)                    .option(ChannelOption.SO_BACKLOG, 1024)                    .childHandler(new ChannelInitializer<SocketChannel>() {                        protected void initChannel(SocketChannel ch) throws Exception {                            ch.pipeline().addLast(new LineBasedFrameDecoder(1024)); //解决粘包拆包                            ch.pipeline().addLast(new StringDecoder());                            ch.pipeline().addLast(new PacketServerHandler());                        }                    });            // 绑定端口,同步等待成功            ChannelFuture f = b.bind(port).sync();            // 等待服务端监听端口关闭            f.channel().closeFuture().sync();        } finally {            // 优雅退出,释放线程池资源            bossGroup.shutdownGracefully();            workerGroup.shutdownGracefully();        }    }    /**     * @param args     * @throws Exception     */    public static void main(String[] args) throws Exception {        int port = 8080;        new PacketServer().bind(port);    }}
public class PacketServerHandler extends ChannelHandlerAdapter {    private int counter;    @Override    public void channelRead(ChannelHandlerContext ctx, Object msg)            throws Exception {        String body = (String) msg;        System.out.println("The time server receive order : " + body                + " ; the counter is : " + ++counter);        String currentTime = "heqing".equalsIgnoreCase(body) ? new java.util.Date(                System.currentTimeMillis()).toString() : "BAD ORDER";        currentTime = currentTime + System.getProperty("line.separator");        ByteBuf resp = Unpooled.copiedBuffer(currentTime.getBytes());        ctx.writeAndFlush(resp);    }    @Override    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {        ctx.close();    }}
public class PacketClient {    public void connect(int port, String host) throws Exception {        // 配置客户端NIO线程组        EventLoopGroup group = new NioEventLoopGroup();        try {            Bootstrap b = new Bootstrap();            b.group(group).channel(NioSocketChannel.class)                    .option(ChannelOption.TCP_NODELAY, true)                    .handler(new ChannelInitializer<SocketChannel>() {                        @Override                        public void initChannel(SocketChannel ch) throws Exception {                            ch.pipeline().addLast(new LineBasedFrameDecoder(1024)); //解决粘包拆包                            ch.pipeline().addLast(new StringDecoder());                            ch.pipeline().addLast(new PacketClientHandler());                        }                    });            // 发起异步连接操作            ChannelFuture f = b.connect(host, port).sync();            // 当代客户端链路关闭            f.channel().closeFuture().sync();        } finally {            // 优雅退出,释放NIO线程组            group.shutdownGracefully();        }    }    /**     * @param args     * @throws Exception     */    public static void main(String[] args) throws Exception {        int port = 8080;        new PacketClient().connect(port, "127.0.0.1");    }}
public class PacketClientHandler extends ChannelHandlerAdapter {    private static final Logger logger = Logger.getLogger(PacketClientHandler.class.getName());    private int counter;    private byte[] req;    public PacketClientHandler() {        req = ("heqing" + System.getProperty("line.separator")).getBytes();    }    @Override    public void channelActive(ChannelHandlerContext ctx) {        ByteBuf message = null;        for (int i = 0; i < 100; i++) {            message = Unpooled.buffer(req.length);            message.writeBytes(req);            ctx.writeAndFlush(message);        }    }    @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 exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {        // 释放资源        logger.warning("Unexpected exception from downstream : "+ cause.getMessage());        ctx.close();    }}

分隔符(DelimiterBasedFrameDecoder)

public class DelimiterServer {    public void bind(int port) throws Exception {        // 配置服务端的NIO线程组        EventLoopGroup bossGroup = new NioEventLoopGroup();        EventLoopGroup workerGroup = new NioEventLoopGroup();        try {            ServerBootstrap b = new ServerBootstrap();            b.group(bossGroup, workerGroup)                .channel(NioServerSocketChannel.class)                .option(ChannelOption.SO_BACKLOG, 100)                .handler(new LoggingHandler(LogLevel.INFO))                .childHandler(new ChannelInitializer<SocketChannel>() {                    @Override                    public 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 DelimiterServerHandler());                    }                });            // 绑定端口,同步等待成功            ChannelFuture f = b.bind(port).sync();            // 等待服务端监听端口关闭            f.channel().closeFuture().sync();        } finally {            // 优雅退出,释放线程池资源            bossGroup.shutdownGracefully();            workerGroup.shutdownGracefully();        }    }    public static void main(String[] args) throws Exception {        int port = 8080;        new DelimiterServer().bind(port);    }}
@Sharablepublic class DelimiterServerHandler extends ChannelHandlerAdapter {    int counter = 0;    @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 += "#_";        ByteBuf echo = Unpooled.copiedBuffer(body.getBytes());        ctx.writeAndFlush(echo);    }    @Override    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {        cause.printStackTrace();        ctx.close();// 发生异常,关闭链路    }}
public class DelimiterClient {    public void connect(int port, String host) throws Exception {        // 配置客户端NIO线程组        EventLoopGroup group = new NioEventLoopGroup();        try {            Bootstrap b = new Bootstrap();            b.group(group).channel(NioSocketChannel.class)                    .option(ChannelOption.TCP_NODELAY, true)                    .handler(new ChannelInitializer<SocketChannel>() {                        @Override                        public 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 DelimiterClientHandler());                        }                    });            // 发起异步连接操作            ChannelFuture f = b.connect(host, port).sync();            // 当代客户端链路关闭            f.channel().closeFuture().sync();        } finally {            // 优雅退出,释放NIO线程组            group.shutdownGracefully();        }    }    /**     * @param args     * @throws Exception     */    public static void main(String[] args) throws Exception {        int port = 8080;        new DelimiterClient().connect(port, "127.0.0.1");    }}
public class DelimiterClientHandler extends ChannelHandlerAdapter {    private int counter;    static final String ECHO_REQ = "heqing.$_";    @Override    public void channelActive(ChannelHandlerContext ctx) {        for (int i = 0; i < 10; i++) {            ctx.writeAndFlush(Unpooled.copiedBuffer(ECHO_REQ.getBytes()));        }    }    @Override    public void channelRead(ChannelHandlerContext ctx, Object msg)            throws Exception {        System.out.println("This is " + (++counter) + " times receive server : ["+ msg + "]");    }    @Override    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {        ctx.flush();    }    @Override    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {        cause.printStackTrace();        ctx.close();    }}

定长解码器(FixedLengthFrameDecoder)

public class FixedLenServer {    public void bind(int port) throws Exception {        // 配置服务端的NIO线程组        EventLoopGroup bossGroup = new NioEventLoopGroup();        EventLoopGroup workerGroup = new NioEventLoopGroup();        try {            ServerBootstrap b = new ServerBootstrap();            b.group(bossGroup, workerGroup)                    .channel(NioServerSocketChannel.class)                    .option(ChannelOption.SO_BACKLOG, 100)                    .handler(new LoggingHandler(LogLevel.INFO))                    .childHandler(new ChannelInitializer<SocketChannel>() {                        @Override                        public void initChannel(SocketChannel ch) throws Exception {                            ch.pipeline().addLast(new FixedLengthFrameDecoder(7));                            ch.pipeline().addLast(new StringDecoder());                            ch.pipeline().addLast(new FixedLenServerHandler());                        }                    });            // 绑定端口,同步等待成功            ChannelFuture f = b.bind(port).sync();            // 等待服务端监听端口关闭            f.channel().closeFuture().sync();        } finally {            // 优雅退出,释放线程池资源            bossGroup.shutdownGracefully();            workerGroup.shutdownGracefully();        }    }    public static void main(String[] args) throws Exception {        int port = 8080;        if (args != null && args.length > 0) {            try {                port = Integer.valueOf(args[0]);            } catch (NumberFormatException e) {                // 采用默认值            }        }        new FixedLenServer().bind(port);    }}
@Sharablepublic class FixedLenServerHandler extends ChannelHandlerAdapter {    @Override    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {        System.out.println("Receive client : [" + msg + "]");        String body = "shanghai";        ByteBuf echo = Unpooled.copiedBuffer(body.getBytes());        ctx.writeAndFlush(echo);    }    @Override    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {        cause.printStackTrace();        ctx.close();// 发生异常,关闭链路    }}
public class FixedLenClient {    public void connect(int port, String host) throws Exception {        // 配置客户端NIO线程组        EventLoopGroup group = new NioEventLoopGroup();        try {            Bootstrap b = new Bootstrap();            b.group(group).channel(NioSocketChannel.class)                    .option(ChannelOption.TCP_NODELAY, true)                    .handler(new ChannelInitializer<SocketChannel>() {                        @Override                        public void initChannel(SocketChannel ch) throws Exception {                            ch.pipeline().addLast(new FixedLengthFrameDecoder(8));                            ch.pipeline().addLast(new StringDecoder());                            ch.pipeline().addLast(new FixedLenClientHandler());                        }                    });            // 发起异步连接操作            ChannelFuture f = b.connect(host, port).sync();            // 当代客户端链路关闭            f.channel().closeFuture().sync();        } finally {            // 优雅退出,释放NIO线程组            group.shutdownGracefully();        }    }    /**     * @param args     * @throws Exception     */    public static void main(String[] args) throws Exception {        int port = 8080;        new FixedLenClient().connect(port, "127.0.0.1");    }}
public class FixedLenClientHandler extends ChannelHandlerAdapter {    private int counter;    static final String ECHO_REQ = "heqing.";    @Override    public void channelActive(ChannelHandlerContext ctx) {        for (int i = 0; i < 10; i++) {            ctx.writeAndFlush(Unpooled.copiedBuffer(ECHO_REQ.getBytes()));        }    }    @Override    public void channelRead(ChannelHandlerContext ctx, Object msg)            throws Exception {        System.out.println("This is " + (++counter) + " times receive server : ["+ msg + "]");    }    @Override    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {        ctx.flush();    }    @Override    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {        cause.printStackTrace();        ctx.close();    }}
0 0
原创粉丝点击