首页 > Web开发 > 详细

netty之 定长数据流处理

时间:2019-06-27 15:04:33      阅读:93      评论:0      收藏:0      [点我收藏+]

一:前言

  基于 https://www.cnblogs.com/zhanyifan/p/11054738.html 进行深入

二:正文

  2.1 建立服务端代码

    2.1.1 创建server端,监听对应的端口(相比于上一篇helloworld的代码比较,仅仅修改了bootstrap.handler中的方法,添加入codec中给定的handler进行处理)

/**
     * 监听处理逻辑
     * @param port 监听端口
     * @return ChannelFuture
     * @throws InterruptedException
     */
    public ChannelFuture doAccept(int port) throws InterruptedException {
        /**
         * childHandler 使bootstrap 独有的方法,是用于提供处理对象的
         * 可以一次性添加若干个处理逻辑,是类似责任链模式处理方式。
         * 增加A,B两个处理逻辑,在处理客户端请求数据的时候,根据A->B 顺序依次处理
         * ChannelInitializer 用于提供处理器的模型对象
         *  其中定义了 initChannel方法,用于初始化处理逻辑责任链的。
         *  可以保证服务端的bootstrap只初始化一次处理器,提供处理逻辑的重用,避免反复创建处理器对象,节约资源
         */
        bootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
            @Override
            protected void initChannel(SocketChannel socketChannel) throws Exception {
                //  定长数据流的修改在此
                ChannelHandler[] acceptorHandlers = new ChannelHandler[3];
                //定长Handler,通过构造函数的参数设置消息长度,发送的消息长度不足可以用空格补全
                //当使用netty codec中的工具类时,必须要引入netty-codec-http依赖
                acceptorHandlers[0] = new FixedLengthFrameDecoder(3);
                //字符串解码器Handler,会自动处理channelRead方法中的msg参数,讲ByteBuf类型的数据转换成String类型
                acceptorHandlers[1] = new StringDecoder(StandardCharsets.UTF_8);
                acceptorHandlers[2] = new Server4FiexedLengthHandler();
                socketChannel.pipeline().addLast(acceptorHandlers);
            }
        });
        //bind 绑定端口,可以绑定多个端口
        //sync 开启监听,返回ChannelFuture,代表监听成功后的一个对应的未来结果
        //可以使用此对象实现后续的服务器和客户端的交互
        return bootstrap.bind(port).sync();
    }

    2.1.2  server端处理逻辑,因为在server端注册了StringDecoder 这个handler,所以此处不用像之前一样进行ByteBuf的转化

import io.netty.buffer.Unpooled;
    import io.netty.channel.ChannelHandler.Sharable;
    import io.netty.channel.ChannelHandlerAdapter;
    import io.netty.channel.ChannelHandlerContext;
    import java.nio.charset.StandardCharsets;
    @Sharable
    public class Server4FiexedLengthHandler extends ChannelHandlerAdapter {
        /**
        * 用户处理读取数据请求的逻辑
        * @param ctx 包含与客户端建立连接的资源,如: 对应的channel
        * @param msg 读取到的数据,默认类型为ByteBuf.是对ByteBuffer的封装
        * @throws Exception
        */
        @Override
        public void channelRead(ChannelHandlerContext ctx,Object msg) throws Exception {
            String message = msg.toString();
            System.out.println("from client:" + message);
            String serverMsg = "ok ";
            ctx.writeAndFlush(Unpooled.copiedBuffer(serverMsg.getBytes(StandardCharsets.UTF_8)));

        }
        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
            System.out.println("server exceptionCaught method run ..... ");
            ctx.close();
        }
    }

  2.2 建立客户端代码

    2.2.1 建立客户端代码,链接服务器对应端口(相比于上一篇helloworld的代码比较,仅仅修改了bootstrap.handler中的方法,添加入codec中给定的handler进行处理)

public ChannelFuture doRequest(String host, int port) throws InterruptedException {
        /**
         * 客户端的bootstrap没有childHandler,只有handler
         *
         * 在客户端必须绑定处理器,也就是必须绑定handler方法。
         * 服务器必须绑定处理器,必须绑定childHandler方法
         */
        this.bootstrap.handler(new ChannelInitializer<SocketChannel>() {
            @Override
            protected void initChannel(SocketChannel socketChannel) throws Exception {
                ChannelHandler[] handlers = new ChannelHandler[3];
                handlers[0] = new FixedLengthFrameDecoder(3);
                //字符串解码器Handler,会自动处理channelRead方法中的msg参数,讲ByteBuf类型的数据转换成String类型
                handlers[1] = new StringDecoder(StandardCharsets.UTF_8);
                handlers[2] = new Client4FixedLengthHandler();

                socketChannel.pipeline().addLast(handlers);
            }
        });
        //connect 连接
        return this.bootstrap.connect(host, port).sync();
    }

    2.2.2 建立客户端处理逻辑,同理,因为注册了StringDecoder这个handler,所以不需要进行ByteBuf的转化

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
import io.netty.util.ReferenceCountUtil;

import java.nio.charset.StandardCharsets;

public class Client4FixedLengthHandler extends ChannelHandlerAdapter {


    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        try{
            String message = msg.toString();
            System.out.println("from server : "+message);
        }finally {
            ReferenceCountUtil.release(msg);
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        System.out.println("client exceptionCaught method run .....");
        ctx.close();
    }
}

三:总结

  利用定长数据流进行数据粘包的处理,主要工作为修改strap的handler方法(即上面对应的server和client中修改的代码),添加codec中已有的一些handler进行相应的处理,即可实现相应的功能

netty之 定长数据流处理

原文:https://www.cnblogs.com/zhanyifan/p/11095134.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!