netty中的channelPipeline在编程中的作用
在netty编程中我们绝大多数是要是用nio的,nio相比传统的io更加高效,而nio中核心概念离不开channel,buffer,selector三个重要的对象。
那么在netty中有一个channelPipeline的概念,表面理解起来是通道的意思,实际它是在数据传输过程中的通道容器。
之所以定义为通道容器就是因为在这里去注册InboundChannelHandle和OnboundChannelHandle。而且netty中设计更为巧妙的是,数据流入和流出的处理器可以是不对称的,当然也有数据出入时同时经过相同的channelHandle处理器。
一张图描绘出netty的数据入栈出栈是可以完全独立的过滤器:

继续跟踪代码并我们会发现,我们经常编写的代码中总是会出现这样的情况:
.childHandler(new ChannelInitializer<SocketChannel>() {
//设置channel中的多个handler
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
ChannelPipeline channelPipeline = socketChannel.pipeline();
ByteBuf delimiter = Unpooled.copiedBuffer("$_$".getBytes());
channelPipeline.addLast("delimiterBasedFrameDecoder", new DelimiterBasedFrameDecoder(4096, delimiter));
channelPipeline.addLast("stringDecoder", new StringDecoder(CharsetUtil.UTF_8));
channelPipeline.addLast("stringEncoder", new StringEncoder(CharsetUtil.UTF_8));
channelPipeline.addLast("testServerChannelHandler", new TestServerChannelHandler());
}
});
public class TestServerChannelHandler extends SimpleChannelInboundHandler<String> {
public static ChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
@Override
protected void channelRead0(ChannelHandlerContext channelHandlerContext, String s) throws Exception {
Channel channel = channelHandlerContext.channel();
channelGroup.forEach(currChannel -> {
if (channel == currChannel) {
currChannel.writeAndFlush("[自己]:" + s + TestServer.delimiterStr);
} else {
currChannel.writeAndFlush("[" + currChannel.remoteAddress().toString() + "]:" + s + TestServer.delimiterStr);
}
});
}
我们会发现在channelRead0中有个ChannelHandlerContext参数,那我们就说下这个Context到底是个什么东西。
我们在addLast方法添加ChannelHandle的时候会发现,有些是继承了ChannelInboundHandle,而有些是继承了ChannelOutboundHandle,另一些是二者都继承了。那么在addlast方法实际调用内部是这样的:
@Override
public final ChannelPipeline addLast(EventExecutorGroup group, String name, ChannelHandler handler) {
final AbstractChannelHandlerContext newCtx;
synchronized (this) {
checkMultiplicity(handler); newCtx = newContext(group, filterName(name, handler), handler);//这里我们实质是创建了一个ChannelHandleContext对象后在调用addLast0方法将上下文对象放入了“事件处理链表”。 addLast0(newCtx); // If the registered is false it means that the channel was not registered on an eventloop yet.
// In this case we add the context to the pipeline and add a task that will call
// ChannelHandler.handlerAdded(...) once the channel is registered.
if (!registered) {
newCtx.setAddPending();
callHandlerCallbackLater(newCtx, true);
return this;
} EventExecutor executor = newCtx.executor();
if (!executor.inEventLoop()) {
newCtx.setAddPending();
executor.execute(new Runnable() {
@Override
public void run() {
callHandlerAdded0(newCtx);
}
});
return this;
}
}
callHandlerAdded0(newCtx);
return this;
}
这里揭示了一个问题,我们要清清楚,并且可以准确的说:channelPipeline是一个容纳channelHandleContext的容器,而容器的内部又持有当前的channel和channelPipeline对象,这些channelHandleContext实际上是组成了一个链表,在数据进行InBound和OutBound
时候进行相应的处理。我们从addLast0方法可以看出是channelHandleContext的链表。如下
private void addLast0(AbstractChannelHandlerContext newCtx) {
AbstractChannelHandlerContext prev = tail.prev;
newCtx.prev = prev;
newCtx.next = tail;
prev.next = newCtx;
tail.prev = newCtx;
}
这里还有个重点问题,我们在使用netty进行实际开发的时候,通过channel对象能获取到writeAndFlush方法将数据写入并发回给客户端。我们知道netty有一系列的
channelHandle控制数据流入和流出,那么在经过OutBoundHandle数据的时候,如果我们调用channel本身的riteAndFlush方法,数据流出会经过所有的ChannelOutBoundHandle
处理器。而如果调用的writeAndFlush方法来自于ChannelHandleContext则只会调用当前handle接下来的ChannelOutBoundHandle处理器,之前的handle处理则不会经过,那么在
这里我们可以根据当前情景适当的选择调用对象,来提升性能。过程如下图:

性能优化点:
(0)对于关注事件发生的EventLoop,尽量使用一个线程来处理,将更多线程分给实际的业务处理。
(1)尽量减小channelpiplen的长度,可减少EventLoop在处理单个事件时的阻塞时间。
(2)减少ChannelHandler的重复创建,可大大减小内存的开销,但是要注意chennelRead的线程安全
(3)对使用完毕的ByteBuf进行引用计数的清除,可对空间进行回收,而且ByteBuf默认是使用堆外内存创建的,堆外内存创建的数据不会用户态和内核态的数据copy大大减少了时间复杂度。
(4).childOption(ChannelOption.TCP_NODELAY, true)和.option(ChannelOption.TCP_NODELAY, true)禁用nagle算法,不等待,马上发送数据,这样数据体积比较小。
netty中的channelPipeline在编程中的作用的更多相关文章
- shell中的输入输出和编程中的变量(shell 03)
shell中的输入输出标准输入:键盘标准输出:终端显示器>> 追加是换行追加的echo -n 不尾随换行符 -e 启用解释反斜杠的转义功能 -E 禁用解释反斜杠的转义功能(默认) --he ...
- Python 3中套接字编程中遇到TypeError: 'str' does not support the buffer interface的解决办法
转自:http://blog.csdn.net/chuanchuan608/article/details/17915959 目前正在学习python,使用的工具为python3.2.3.发现3x版本 ...
- 一文读懂高性能网络编程中的I/O模型
1.前言 随着互联网的发展,面对海量用户高并发业务,传统的阻塞式的服务端架构模式已经无能为力.本文(和下篇<高性能网络编程(六):一文读懂高性能网络编程中的线程模型>)旨在为大家提供有用的 ...
- (转)Spring Boot 2 (十):Spring Boot 中的响应式编程和 WebFlux 入门
http://www.ityouknow.com/springboot/2019/02/12/spring-boot-webflux.html Spring 5.0 中发布了重量级组件 Webflux ...
- Java网络编程中异步编程的理解
目录 前言 一.异步,同步,阻塞和非阻塞的理解 二.异步编程从用户层面和框架层面不同角度的理解 用户角度的理解 框架角度的理解 三.为什么使用异步 四.理解这些能在实际中的应用 六.困惑 参考文章 前 ...
- Spring Boot 2 (十):Spring Boot 中的响应式编程和 WebFlux 入门
Spring 5.0 中发布了重量级组件 Webflux,拉起了响应式编程的规模使用序幕. WebFlux 使用的场景是异步非阻塞的,使用 Webflux 作为系统解决方案,在大多数场景下可以提高系统 ...
- Fixed-Length Frames 谈谈网络编程中应用层(基于TCP/UDP)的协议设计
http://blog.sina.com.cn/s/blog_48d4cf2d0101859x.html 谈谈网络编程中应用层(基于TCP/UDP)的协议设计 (2013-04-27 19:11:00 ...
- Java并发编程中的若干核心技术,向高手进阶!
来源:http://www.jianshu.com/p/5f499f8212e7 引言 本文试图从一个更高的视角来总结Java语言中的并发编程内容,希望阅读完本文之后,可以收获一些内容,至少应该知道在 ...
- .Net中的反应式编程(Reactive Programming)
系列主题:基于消息的软件架构模型演变 一.反应式编程(Reactive Programming) 1.什么是反应式编程:反应式编程(Reactive programming)简称Rx,他是一个使用LI ...
随机推荐
- 常用方法 读取 Excel的单位格 为 日期格式 的数据
原文:地址忘了 百度应该有 Excel的单元格为日期格式,数值型日期,可用下面这个方法得到正常的数据 /// <summary> /// 数字格式的时间 转换为 字符串格式的时间 /// ...
- uni-app 组件
组件:组件时视图层的基本组成单元 <template> <view> <tagname property = "value"> content ...
- 设置Git--在Git中设置您的用户名--创建一个回购--Fork A Repo--社会化
设置Git GitHub的核心是名为Git的开源版本控制系统(VCS).Git负责计算机上本地发生的所有GitHub相关的事情. 要在命令上使用Git,您需要在计算机上下载,安装和配置Git. 如果要 ...
- X86 下的SSDT HOOK
目录 SSDTHOOK 1.SSDTHOOK 原理. 1.x32下的SSDT HOOK 2.SSDT HOOK代码 3.结果 4.总结 SSDTHOOK 1.SSDTHOOK 原理. x32下,直接获 ...
- [后渗透]获取到 Meterpreter 之后的操作
sysinfo 列出受控主机的系统信息 ls 列出目标主机的文件和文件夹信息 use priv 加载特权提升扩展模块,来扩展meterpreter库 ps 显示所有运行进程以及关联的用户账户 gets ...
- GCC编译UDF和gdb调试UDF
Fluent版本:19.0 前面我们介绍过使用VS来编译和调试UDF,其实我们也可以用GCC来编译UDF.gdb调试UDF.本次介绍的方法更具有通用性,也适用于Linux下Fluent的UDF编译和调 ...
- layui之table.render使用(含后台详细代码实现)
效果图如下: 前端实现代码如图(完整代码): <!DOCTYPE html> <html> <head> <meta charset="utf-8& ...
- zabbix 同步ldap帐号脚本
1.界面配置ldap验证(略) 2.mysql导入ldap帐号信息 #!/usr/bin/env python# -*- coding:utf-8 -*- import pymysqlimport c ...
- 【Beta】Scrum meeting 7
目录 写在前面 进度情况 任务进度表 Beta-1阶段燃尽图 遇到的困难 照片 commit截图记录 后端代码仓库 技术博客 写在前面 例会时间:5.11 22:30-22:50 例会地点:微信群语音 ...
- [Gamma阶段]第二次Scrum Meeting
Scrum Meeting博客目录 [Gamma阶段]第二次Scrum Meeting 基本信息 名称 时间 地点 时长 第二次Scrum Meeting 19/05/28 大运村寝室6楼 20min ...