[英]Decoder, Encoder, ServerHandler pipeline in netty
查看文档,它说:
https://netty.io/4.0/api/io/netty/channel/ChannelPipeline.html
用户应该在管道中有一个或多个 ChannelHandler 来接收 I/O 事件(例如读取)和请求 I/O 操作(例如写入和关闭)。 例如,典型的服务器将在每个通道的管道中具有以下处理程序,但您的里程可能会因协议和业务逻辑的复杂性和特征而异:
协议解码器 - 将二进制数据(例如 ByteBuf)转换为 Java 对象。 协议编码器 - 将 Java 对象转换为二进制数据。
业务逻辑处理程序 - 执行实际的业务逻辑(例如数据库访问)。 它可以表示为如下示例所示: static final EventExecutorGroup group = new DefaultEventExecutorGroup(16); ...
ChannelPipeline 管道 = ch.pipeline();
pipeline.addLast("decoder", new MyProtocolDecoder());
pipeline.addLast("encoder", new MyProtocolEncoder());
// 告诉管道在与 I/O 线程不同的线程中 // 运行 MyBusinessLogicHandler 的事件处理程序方法,以便 I/O 线程不会被耗时的任务阻塞 //。 // 如果您的业务逻辑是完全异步的或很快完成,您就不需要 // 指定一个组。
pipeline.addLast(group, "handler", new MyBusinessLogicHandler());
在 Github 上的许多示例中,我看到了相同的模式。 我想知道是否有人可以解释为什么 businessHandler 不在解码器和编码器之间。 我认为你会得到你的 POJO,然后在业务处理程序中处理它,然后对它进行编码。
由于调用处理程序的顺序,解码器和编码器通常位于管道的开头。 对于传入的数据,它是自下而上的,而传出的数据是自上而下的。
例如
pipeline.addLast(new MyEncoder());
pipeline.addLast(new MyDecoder());
pipeline.addLast(new MyBusiness());
在这种情况下,传入数据的调用顺序是:MyDecoder(将数据转换为POJO)-> MyBusiness(传入流不调用编码器),传出数据:MyBusiness -> MyEncoder(传出流不调用解码器) .
如果您在业务处理程序(实际上是解码器之后的 POJO)中接收到传入流并将其写回,则看起来 MyBusiness 位于编码器和解码器之间,因为数据正在返回编码器。
当然,业务处理程序介于解码器和编码器之间。以 Factorial 示例为例。
public void initChannel(SocketChannel ch) {
ChannelPipeline pipeline = ch.pipeline();
if (sslCtx != null) {
pipeline.addLast(sslCtx.newHandler(ch.alloc()));
}
// Enable stream compression (you can remove these two if unnecessary)
pipeline.addLast(ZlibCodecFactory.newZlibEncoder(ZlibWrapper.GZIP));
pipeline.addLast(ZlibCodecFactory.newZlibDecoder(ZlibWrapper.GZIP));
// Add the number codec first,
pipeline.addLast(new BigIntegerDecoder());
pipeline.addLast(new NumberEncoder());
// and then business logic.
// Please note we create a handler for every new channel
// because it has stateful properties.
pipeline.addLast(new FactorialServerHandler());
}`
在initChannel
的函数中initChannel
pipeline先添加encoder和decoder,最后添加handler。 执行流程实际上是按解码器、处理程序和编码器排序的。 解码器、处理程序和编码器等处理程序实际上存储在AbstractChannelHandlerContext
类中。 Netty 中有一个AbstractChannelHandlerContext
的链表。 列表的排列方式是decoder context
--> handler context
--> encoder context
,执行是一样的!
事实上,如果你在你的服务器中添加ctx.channel().writeAndFlush()
,并且你编写ctx.channel().writeAndFlush()
或ctx.pipeline().writeAndFlush()
,那么编码器将被调用. 在这种情况下是 bc,它将从尾部开始寻找上一个 outboundChannel。 但是,如果您编写ctx.writeAndFlush()
,它将从 businessHandler 的位置查找上一个 outboundChannel。 在AbstractChannelHandlerContext的findContextOutbound()
的第一行加断点,就搞定了。
private AbstractChannelHandlerContext findContextOutbound(int mask) {
AbstractChannelHandlerContext ctx = this;
EventExecutor currentExecutor = executor();
do {
ctx = ctx.prev;
} while (skipContext(ctx, currentExecutor, mask, MASK_ONLY_OUTBOUND));
return ctx;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.