彻底搞懂 Netty 线程模型( 五 )

客户端自定义回调函数:
package com.niuh.netty.base;import io.netty.buffer.ByteBuf;import io.netty.buffer.Unpooled;import io.netty.channel.ChannelHandlerContext;import io.netty.channel.ChannelInboundHandlerAdapter;import io.netty.util.CharsetUtil;public class NettyClientHandler extends ChannelInboundHandlerAdapter {    /**     * 当客户端连接服务器完成就会触发该方法     *     * @param ctx     * @throws Exception     */    @Override    public void channelActive(ChannelHandlerContext ctx) throws Exception {        ByteBuf buf = Unpooled.copiedBuffer("HelloServer".getBytes(CharsetUtil.UTF_8));        ctx.writeAndFlush(buf);    }    //当通道有读取事件时会触发,即服务端发送数据给客户端    @Override    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {        ByteBuf buf = (ByteBuf) msg;        System.out.println("收到服务端的消息:" + buf.toString(CharsetUtil.UTF_8));        System.out.println("服务端的地址: " + ctx.channel().remoteAddress());    }    @Override    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {        cause.printStackTrace();        ctx.close();    }}与NettyServerHandler类似,其中的channelActive()方法是当客户端与服务器连接完成时候就会执行的方法 。

看完代码,我们发现Netty架的目标就是让你的业务逻辑从网络基础应用编码中分离出来,让你可以专 注业务的开发,而不需写一大堆类似NIO的网络处理操作 。
ByteBuf 理解从结构上来说,ByteBuf 由一串字节数组构成 。数组中每个字节用来存放信息 。
ByteBuf 提供了两个索引,一个用于读取数据,一个用于写入数据 。这两个索引通过在字节数组中移动,来定位需要读或者写信息的位置 。
  • 当从 ByteBuf 读取时,它的 readerIndex(读索引)将会根据读取的字节数递增 。
  • 同样,当写 ByteBuf 时,它的 writerIndex 也会根据写入的字节数进行递增 。

彻底搞懂 Netty 线程模型

文章插图
 
ByteBuf.png
需要注意的是极限的情况是 readerIndex 刚好读到了 writerIndex 写入的地方 。如果 readerIndex 超过了 writerIndex 的时候,Netty 会抛出 IndexOutOf-BoundsException 异常 。
示例代码package com.niuh.netty.base;import io.netty.buffer.ByteBuf;import io.netty.buffer.Unpooled;import io.netty.util.CharsetUtil;public class NettyByteBuf {    public static void main(String[] args) {        // 创建byteBuf对象,该对象内部包含一个字节数组byte[10]        // 通过readerindex和writerIndex和capacity,将buffer分成三个区域        // 已经读取的区域:[0,readerindex)        // 可读取的区域:[readerindex,writerIndex)        // 可写的区域: [writerIndex,capacity)        ByteBuf byteBuf = Unpooled.buffer(10);        System.out.println("byteBuf=" + byteBuf);        for (int i = 0; i < 8; i++) {            byteBuf.writeByte(i);        }        System.out.println("byteBuf=" + byteBuf);        for (int i = 0; i < 5; i++) {            System.out.println(byteBuf.getByte(i));        }        System.out.println("byteBuf=" + byteBuf);        for (int i = 0; i < 5; i++) {            System.out.println(byteBuf.readByte());        }        System.out.println("byteBuf=" + byteBuf);        //用Unpooled工具类创建ByteBuf        ByteBuf byteBuf2 = Unpooled.copiedBuffer("hello,zhangsan!", CharsetUtil.UTF_8);        //使用相关的方法        if (byteBuf2.hasArray()) {            byte[] content = byteBuf2.array();            //将 content 转成字符串            System.out.println(new String(content, CharsetUtil.UTF_8));            System.out.println("byteBuf=" + byteBuf2);            System.out.println(byteBuf2.readerIndex()); // 0            System.out.println(byteBuf2.writerIndex()); // 12            System.out.println(byteBuf2.capacity()); // 36            System.out.println(byteBuf2.getByte(0)); // 获取数组0这个位置的字符h的ascii码,h=104            int len = byteBuf2.readableBytes(); //可读的字节数  12            System.out.println("len=" + len);            //使用for取出各个字节            for (int i = 0; i < len; i++) {                System.out.println((char) byteBuf2.getByte(i));            }            //范围读取            System.out.println(byteBuf2.getCharSequence(0, 6, CharsetUtil.UTF_8));            System.out.println(byteBuf2.getCharSequence(6, 6, CharsetUtil.UTF_8));        }    }}


推荐阅读