本文目的:测试数据在ChannelPipeline中的流经顺序及状态。

先看本文的测试代码:

AdditionalInBoundHandler:入站处理器,不做任何处理,只是在响应读事件时打印用来观察,并继续通过fireChannelRead传递读事件。

public class AdditionalInBoundHandler extends ChannelInboundHandlerAdapter {
private String name; public AdditionalInBoundHandler(String name){
this.name = name;
} @Override
public void channelRead(ChannelHandlerContext ctx, Object msg){
System.out.println("go through additional InBoundHandler[" + name + "]; msg type[" + msg.getClass() + "]");
ctx.fireChannelRead(msg);
}
}

BigIntegerDecoder:解码器,用来读取Bytebuf中的字节数据,解码成BigInter对象。

public class BigIntegerDecoder extends ByteToMessageDecoder {

    @Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) {
System.out.println("BigIntegerDecoder");
// Wait until the length prefix is available.
if (in.readableBytes() < 4) {
return;
}
in.markReaderIndex(); int length = in.readInt();
if (in.readableBytes() < length){
in.resetReaderIndex();
return;
}
byte[] data = new byte[length];
in.readBytes(data); out.add(new BigInteger(data));
}

NettyServerHandler:将读到的BigInteger加1并写出。

public class NettyServerHandler extends SimpleChannelInboundHandler<BigInteger> {

    @Override
public void channelRead0(ChannelHandlerContext ctx, BigInteger msg) throws Exception {
System.out.println("NettyServerHandler");
ctx.writeAndFlush(msg.add(BigInteger.ONE));
} @Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}

NumberEncoder:将BigInteger对象编码成字节数字,由ByteBuf写出。

public class NumberEncoder extends MessageToByteEncoder<Number> {

    @Override
protected void encode(ChannelHandlerContext ctx, Number msg, ByteBuf out) {
System.out.println("NumberEncoder");
// Convert to a BigInteger first for easier implementation.
BigInteger v;
if (msg instanceof BigInteger) {
v = (BigInteger) msg;
} else {
v = new BigInteger(String.valueOf(msg));
} // Convert the number into a byte array.
byte[] data = v.toByteArray();
int dataLength = data.length; // Write a message.
out.writeInt(dataLength); // data length
out.writeBytes(data); // data
}
}

AdditionalOutboundHandler:出站处理器,不对数据做任何处理,直接写出,只是简单增加了打印功能,方便测试。

public class AdditionalOutBoundHandler extends ChannelOutboundHandlerAdapter {
private String name; public AdditionalOutBoundHandler(String name) {
this.name = name;
} @Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
System.out.println("go through additional outbound handler[" + name + "];msg type [" + msg.getClass() + "]");
ctx.write(msg, promise);
}
}

测试代码:channelHandlerTest。通过EmbeddedChannel进行测试。

public class ChannelHandlerTest {

    @Test
public void channelHandlerTest(){
ByteBuf buf = Unpooled.buffer(); EmbeddedChannel embeddedChannel = new EmbeddedChannel(); ChannelPipeline pipeline = embeddedChannel.pipeline(); pipeline.addLast(new AdditionalInBoundHandler("in handler 1"));
pipeline.addLast(new AdditionalInBoundHandler("in handler 2"));
pipeline.addLast(new BigIntegerDecoder());
pipeline.addLast(new NumberEncoder()); pipeline.addLast(new AdditionalOutBoundHandler("out handler 1"));
pipeline.addLast(new AdditionalInBoundHandler("in handler 3"));
pipeline.addLast(new NettyServerHandler());
pipeline.addLast(new AdditionalInBoundHandler("in handler 4"));
pipeline.addLast(new AdditionalOutBoundHandler("out handler 2")); byte[] bytes = new byte[]{0x01, 0x02, 0x03, 0x04};
BigInteger bi = new BigInteger(bytes); buf.writeInt(4);
buf.writeBytes(bytes); //因为nettyServerHandler fire了写事件,因此channelpipeline尾部没数据可读
assertTrue(!embeddedChannel.writeInbound(buf)); ByteBuf readBuf = embeddedChannel.readOutbound();
int length = readBuf.readInt();
bytes = new byte[length];
readBuf.readBytes(bytes);
System.out.println(new BigInteger(bytes));
}
}

我们可以看到ChannelPipeline中的顺序是头到尾:InBound1(入) -> InBound2(入) -> BigIntegerDecoder(入) -> NumberEncoder(出) -> OutBound1(出) -> InBound3(入) -> NettyServerHandler(入) -> InBound4(入) -> OutBound2(出)。

执行测试代码,我们可以看到控制台中的输出是:

我们通过一张流程图片更清晰的看一下整个流经过程以及数据的状态:

图上的箭头很清楚的表示了数据流经的过程,[XXX则注释出了此时的数据对象。

入站数据沿着ChannelPipeline的头至尾依次寻找下一个可以处理对应消息的处理器。

出战数据则会沿着ChannelPipeline的尾至头依次寻找下一个可以处理对应消息的处理器。

比如为什么数据没有流经InBoundHandler4和OutBoundHandler2?

因为NettyServerHandler发出了一个写事件,因此数据从尾至头的方法找下一个可以处理写消息的处理器,即OutBoundHandler1,在顺延下去。

Netty(二):数据在ChannelPipeline中的流经的更多相关文章

  1. SpringMVC(二)返回值设置、数据在域中的保存与SpringMVC案例

    个人博客网:https://wushaopei.github.io/    (你想要这里多有) 一.返回值的设置 1.返回 String [1]返回 String 默认情况 @RequestMappi ...

  2. Scrapy基础(十二)————异步导出Item数据到Mysql中

    异步导出数据到Mysql中 上次说过从Item中同步写入数据库,因为网络的下载速度和数据库的I/O速度是不一样的所以有可能会发生下载快,但是写入数据库速度慢,造成线程的堵塞:关于堵塞和非堵塞,同步和异 ...

  3. 【Netty】ChannelHandler和ChannelPipeline

    一.前言 前面学习了Netty的ByteBuf,接着学习ChannelHandler和ChannelPipeline. 二.ChannelHandler和ChannelPipeline 2.1 Cha ...

  4. 一个I/O线程可以并发处理N个客户端连接和读写操作 I/O复用模型 基于Buf操作NIO可以读取任意位置的数据 Channel中读取数据到Buffer中或将数据 Buffer 中写入到 Channel 事件驱动消息通知观察者模式

    Tomcat那些事儿 https://mp.weixin.qq.com/s?__biz=MzI3MTEwODc5Ng==&mid=2650860016&idx=2&sn=549 ...

  5. 在dubbo的一端,看Netty处理数据包,揭网络传输原理

    如今,我们想要开发一个网络应用,那是相当地方便.不过就是引入一个框架,然后设置些参数,然后写写业务代码就搞定了. 写业务代码自然很重要,但是你知道: 你的数据是怎么来的吗?通过网络传输过来的呗. 你知 ...

  6. 自顶向下深入分析Netty(七)--ChannelPipeline和ChannelHandler总述

    自顶向下深入分析Netty(七)--ChannelPipeline和ChannelHandler总述 自顶向下深入分析Netty(七)--ChannelPipeline源码实现 自顶向下深入分析Net ...

  7. Netty(二):如何处理io请求?

    文接上一篇.上篇讲到netty暴露一个端口出来,acceptor, handler, pipeline, eventloop 都已准备好.但是并没体现其如何处理接入新的网络请求,今天我们就一起来看看吧 ...

  8. 一文搞懂 Netty 发送数据全流程 | 你想知道的细节全在这里

    欢迎关注公众号:bin的技术小屋,如果大家在看文章的时候发现图片加载不了,可以到公众号查看原文 本系列Netty源码解析文章基于 4.1.56.Final版本 在<Netty如何高效接收网络数据 ...

  9. (转)原始图像数据和PDF中的图像数据

    比较原始图像数据和PDF中的图像数据,结果见表1.1.表1.1中各种“解码器”的解释见本文后续的“PDF支持的图像格式”部分,“PDF中的图像数据”各栏中的数据来自开源的PdfView.如果您有兴趣查 ...

随机推荐

  1. ssh 解决经常断开与记住密码功能

    一.解决ssh经常自动断开问题 修改 /etc/ssh/sshd_config 其中对应项为 ClientAliveInterval 30 ClientAliveCountMax 3 表示每30秒发一 ...

  2. CentOS虚拟机开机显示多内核版本

    在CentOS进行系统更新后,会保留旧版本的内核.所以,在每次启动时,会有多个内核选项,可以手动删除不用的旧版本内核.   1.查看当前系统内核版本 #uname -a   2.查看系统中存在的全部内 ...

  3. Springboot系列(四)web静态资源配置详解

    Springboot系列(四)web静态资源配置 往期精彩 SpringBoot系列(一)idea新建Springboot项目 SpringBoot系列(二)入门知识 SpringBoot系列(三)配 ...

  4. 独立Web站点的快速部署

                                                                  独立Web站点的快速部署 1案例1:独立Web站点的快速部署 1.1问题 本 ...

  5. zabbix模板的自动发现规则(ldd)实现被监控项自动发现

    zabbix模板的自动发现规则(ldd)实现被监控项自动发现 自动发现规则(ldd)用途说明 在zabbix自带的linux模板的自动发现规则中,有一个Mounted filesystem disco ...

  6. es elasticsearch 6/7 设置内存方法

    es节点的默认的heap内存大小是 1G 大小,在实际生产中,很容易导致内存溢出而导致进程被kill掉.所以我们一般会自己配置自己的,2.x的版本可以通过export ES_HEAP_SIZE=10g ...

  7. 34.4 对象流 ObjectOutputStream ObjectInputStream

    * 对象操作流:可以用于读写任意类型的对象 * ObjectOutputStream * writeObject * ObjectOutputStream(OutputStream out) * Ob ...

  8. "文本"组件:<text> —— 快应用原生组件

     <template> <div class="container"> <text>H-UI</text> </div> ...

  9. Mac OS安装docker

    MacOS Docker 安装 使用 Homebrew 安装 macOS 我们可以使用 Homebrew 来安装 Docker. Homebrew 的 Cask 已经支持 Docker for Mac ...

  10. qt creator源码全方面分析(4-1)

    目录 d指针和q指针 简单示例 q指针 QObject和QObjectPrivate qtcreator中的变体1 qtcreator中的变体2 小结 d指针和q指针 我们在类成员名称和使用d指针中, ...