1.Channel
channel 是负责数据读,写的对象,有点类似于老的io里面的stream。它和stream的区别,channel是双向的,既可以write 也可以read,而stream要分outstream和inputstream。而且在NIO中用户不应该直接从channel中读写数据,而是应该通过buffer,通过buffer再将数据读写到channel中。
一个channel 可以提供给用户下面几个信息
(1)channel的当前状态,比如open 还是closed
(2)ChannelConfig对象,表示channel的一些参数,比如bufferSize
(3)channel支持的所有i/o操作(比如read,write,connect.bind)以及ChannelPipeLine(下面解释)
2.ChannelConfig
channel的参数,以Map 数据结构来存储
3.ChannelEvent
ChannelEvent广义的认为Channel相关的事件,它是否分Upstream events和downstream events两大块,这里需要注意的,若是以server为主体的话,从client的数据到server的过程是Upstream;而server到client的数据传输过程叫downstream;而如果以client为主体的话,从server到client的过程对client来说是Upstream,而client到server的过程对client来说就是downstream。
Upstream events包括:
messageReceived:信息被接受时 ---MessageEvent
exceptionCaught:产生异常时 ---ExceptionEvent
channelOpen:channel被开启时 ---ChannelStateEvent
channelClosed:channel被关闭时 ---ChannelStateEvent
channelBound:channel被开启并准备去连接但还未连接上的时候 ---ChannelStateEvent
channelUnbound:channel被开启不准备去连接时候 ---ChannelStateEvent
channelConnected:channel被连接上的时候 ---ChannelStateEvent
channelDisconnected:channel连接断开的时候 ---ChannelStateEvent
channelInterestChanged:Channel的interestOps被改变的时候 ------ChannelStateEvent
writeComplete:写到远程端完成的时候 --WriteCompletionEvent
Downstream events包括:
write:发送信息给channel的时候 --MessageEvent
bind:绑定一个channel到指定的本地地址 --ChannelStateEvent
unbind:解除当前本地端口的绑定--ChannelStateEvent
connect:将channel连接到远程的机 --ChannelStateEvent
disconnect:将channel与远程的机连接断开 --ChannelStateEvent
close:关闭channel --ChannelStateEvent
需要注意的是,这里没有open event,这是因为当一个channel被channelFactory创建的话,channel总是已经被打开了。
此外还有两个事件类型是当父channel存在子channel的情况
childChannelOpen:子channel被打开 ---ChannelStateEvent
childChannelClosed:子channel被关闭 ---ChannelStateEvent
4.ChannelHandler
channel是负责传送数据的载体,那么数据肯定需要根据要求进行加工处理,那么这个时候就用到ChannelHandler
不同的加工可以构建不同的ChannelHandler,然后放入ChannelPipeline中
此外需要有ChannelEvent触发后才能到达ChannelHandler,因此根据event不同有下面两种的sub接口ChannelUpstreamHandler
和ChannelDownstreamHandler。
一个ChannelHandler通常需要存储一些状态信息作为判断信息,常用做法定义一个变量
比如
public class DataServerHandler extends {@link SimpleChannelHandler} {
*
* <b>private boolean loggedIn;</b>
*
* {@code @Override}
* public void messageReceived({@link ChannelHandlerContext} ctx, {@link MessageEvent} e) {
* {@link Channel} ch = e.getChannel();
* Object o = e.getMessage();
* if (o instanceof LoginMessage) {
* authenticate((LoginMessage) o);
* <b>loggedIn = true;</b>
* } else (o instanceof GetDataMessage) {
* if (<b>loggedIn</b>) {
* ch.write(fetchSecret((GetDataMessage) o));
* } else {
* fail();
* }
* }
* }
* ...
* }
// Create a new handler instance per channel.
* // See {@link Bootstrap#setPipelineFactory(ChannelPipelineFactory)}.
* public class DataServerPipelineFactory implements {@link ChannelPipelineFactory} {
* public {@link ChannelPipeline} getPipeline() {
* return {@link Channels}.pipeline(<b>new DataServerHandler()</b>);
* }
* }
除了这种,每个ChannelHandler都可以从ChannelHandlerContext中获取或设置数据,那么下面的做法就是利用ChannelHandlerContext
设置变量
* {@code @Sharable}
* public class DataServerHandler extends {@link SimpleChannelHandler} {
*
* {@code @Override}
* public void messageReceived({@link ChannelHandlerContext} ctx, {@link MessageEvent} e) {
* {@link Channel} ch = e.getChannel();
* Object o = e.getMessage();
* if (o instanceof LoginMessage) {
* authenticate((LoginMessage) o);
* <b>ctx.setAttachment(true)</b>;
* } else (o instanceof GetDataMessage) {
* if (<b>Boolean.TRUE.equals(ctx.getAttachment())</b>) {
* ch.write(fetchSecret((GetDataMessage) o));
* } else {
* fail();
* }
* }
* }
* ...
* }
* public class DataServerPipelineFactory implements {@link ChannelPipelineFactory} {
*
* private static final DataServerHandler <b>SHARED</b> = new DataServerHandler();
*
* public {@link ChannelPipeline} getPipeline() {
* return {@link Channels}.pipeline(<b>SHARED</b>);
* }
* }
这两种做法还是有区别的,上面的变量做法,每个new的handler 对象,变量是不共享的,而下面的ChannelHandlerContext是共享的
如果需要不同的handler之间共享数据,那怎么办,那就用ChannelLocal
例子:
public final class DataServerState {
*
* <b>public static final {@link ChannelLocal}<Boolean> loggedIn = new {@link ChannelLocal}<Boolean>() {
* protected Boolean initialValue(Channel channel) {
* return false;
* }
* }</b>
* ...
* }
*
* {@code @Sharable}
* public class DataServerHandler extends {@link SimpleChannelHandler} {
*
* {@code @Override}
* public void messageReceived({@link ChannelHandlerContext} ctx, {@link MessageEvent} e) {
* Channel ch = e.getChannel();
* Object o = e.getMessage();
* if (o instanceof LoginMessage) {
* authenticate((LoginMessage) o);
* <b>DataServerState.loggedIn.set(ch, true);</b>
* } else (o instanceof GetDataMessage) {
* if (<b>DataServerState.loggedIn.get(ch)</b>) {
* ctx.getChannel().write(fetchSecret((GetDataMessage) o));
* } else {
* fail();
* }
* }
* }
* ...
* }
*
* // Print the remote addresses of the authenticated clients:
* {@link ChannelGroup} allClientChannels = ...;
* for ({@link Channel} ch: allClientChannels) {
* if (<b>DataServerState.loggedIn.get(ch)</b>) {
* System.out.println(ch.getRemoteAddress());
* }
* }
* </pre>
5.ChannelPipeline
channelPipeline是一系列channelHandler的集合,他参照J2ee中的Intercepting Filter模式来实现的,让用户完全掌握如果在一个handler中处理事件,同时让pipeline里面的多个handler可以相互交互。
Intercepting Filter:http://java.sun.com/blueprints/corej2eepatterns/Patterns/InterceptingFilter.html 对于每一个channel都需要有相应的channelPipeline,当为channel设置了channelPipeline后就不能再为channel重新设置 channelPipeline。此外建议的做法的通过Channels 这个帮助类来生成ChannelPipeline 而不是自己去构建ChannelPipeline
通常pipeLine 添加多个handler,是基于业务逻辑的
比如下面
{@link ChannelPipeline} p = {@link Channels}.pipeline();
* p.addLast("1", new UpstreamHandlerA());
* p.addLast("2", new UpstreamHandlerB());
* p.addLast("3", new DownstreamHandlerA());
* p.addLast("4", new DownstreamHandlerB());
* p.addLast("5", new SimpleChannelHandler());
upstream event 执行的handler按顺序应该是 125
downstream event 执行的handler按顺序应该是 543
SimpleChannelHandler 是同时实现了 ChannelUpstreamHandler和ChannelDownstreamHandler的类
上面只是具有逻辑,如果数据需要通过格式来进行编码的话,那需要这些写
* {@link ChannelPipeline} pipeline = {@link Channels#pipeline() Channels.pipeline()};
* pipeline.addLast("decoder", new MyProtocolDecoder());
* pipeline.addLast("encoder", new MyProtocolEncoder());
* pipeline.addLast("executor", new {@link ExecutionHandler}(new {@link OrderedMemoryAwareThreadPoolExecutor}(16, 1048576, 1048576)));
* pipeline.addLast("handler", new MyBusinessLogicHandler());
其中:
Protocol Decoder - 将binary转换为java对象
Protocol Encoder - 将java对象转换为binary
ExecutionHandler - applies a thread model.
Business Logic Handler - performs the actual business logic(e.g. database access)
虽然不能为channel重新设置channelPipeline,但是channelPipeline本身是thread-safe,因此你可以在任何时候为channelPipeline添加删除channelHandler
需要注意的是,下面的代码写法不能达到预期的效果
* public class FirstHandler extends {@link SimpleChannelUpstreamHandler} {
*
* {@code @Override}
* public void messageReceived({@link ChannelHandlerContext} ctx, {@link MessageEvent} e) {
* // Remove this handler from the pipeline,
* ctx.getPipeline().remove(this);
* // And let SecondHandler handle the current event.
* ctx.getPipeline().addLast("2nd", new SecondHandler());
* ctx.sendUpstream(e);
* }
* }
前提现在Pipeline只有最后一个FirstHandler,
上面明显是想把FirstHandler从Pipeline中移除,然后添加SecondHandler。而pipeline需要有一个Handler,因此如果想到到达这个效果,那么可以
先添加SecondHandler,然后在移除FirstHandler。
6.ChannelFactory
channel的工厂类,也就是用来生成channel的类,ChannelFactory根据指定的通信和网络来生成相应的channel,比如
NioServerSocketChannelFactory生成的channel是基于NIO server socket的。
当一个channel创建后,ChannelPipeline将作为参数附属给该channel。
对于channelFactory的关闭,需要做两步操作
第一,关闭所有该factory产生的channel包括子channel。通常调用ChannelGroup#close()。
第二,释放channelFactory的资源,调用releaseExternalResources()
7.ChannelGroup
channel的组集合,他包含一个或多个open的channel,closed channel会自动从group中移除,一个channel可以在一个或者多个channelGroup
如果想将一个消息广播给多个channel,可以利用group来实现
比如:
{@link ChannelGroup} recipients = new {@link DefaultChannelGroup}()
recipients.add(channelA);
recipients.add(channelB);
recipients.write(ChannelBuffers.copiedBuffer("Service will shut down for maintenance in 5 minutes.",CharsetUtil.UTF_8));
当ServerChannel和非ServerChannel同时都在channelGroup中的时候,任何io请求的操作都是先在ServerChannel中执行再在其他Channel中执行。
这个规则对关闭一个server非常适用。
8.ChannelFuture
在netty中,所有的io传输都是异步,所有那么在传送的时候需要数据+状态来确定是否全部传送成功,而这个载体就是ChannelFuture。
9.ChannelGroupFuture
针对一次ChannelGroup异步操作的结果,他和ChannelFuture一样,包括数据和状态。不同的是他由channelGroup里面channel的所有channelFuture 组成。
10.ChannelGroupFutureListener
针对ChannelGroupFuture的监听器,同样建议使用ChannelGroupFutureListener而不是await();
11.ChannelFutureListener
ChannelFuture监听器,监听channelFuture的结果。
12.ChannelFutureProgressListener
监听ChannelFuture处理过程,比如一个大文件的传送。而ChannelFutureListener只监听ChannelFuture完成未完成
13.ChannelHandlerContext
如何让handler和他的pipeLine以及pipeLine中的其他handler交换,那么就要用到ChannelHandlerContext,ChannelHandler可以通过ChannelHandlerContext的sendXXXstream(ChannelEvent)将event传给最近的handler ,可以通过ChannelHandlerContext的getPipeline来得到Pipeline,并修改他,ChannelHandlerContext还可以存放一下状态信息attments。
一个ChannelHandler实例可以有一个或者多个ChannelHandlerContext
14.ChannelPipelineFactory
产生ChannelPipe的工厂类
15.ChannelState
记载channel状态常量
相关推荐
* Netty Channel:在 JAVA 技术栈中,gRPC 的数据传输用的是 Netty Channel。 * Protocol Buffers:一种压缩率极高的序列化协议。 RESTful API 设计是一种架构风格,它有很大的灵活性,可以实现客户端与服务端之间...
内容概要:本文详细介绍了如何利用LTspice进行LDO(低压差线性稳压器)电源电路的仿真。首先讲解了如何导入LDO模型并配置仿真环境,接着深入探讨了瞬态分析、相位裕度、电源抑制比(PSRR)等关键仿真的具体步骤和注意事项。文中提供了多个实用的操作技巧,如通过调整补偿电容优化相位裕度,以及使用.step param命令批量测试不同参数的影响。此外,还分享了一些常见的仿真误区及其解决方法,帮助读者更好地理解和掌握LDO的设计与调试。 适合人群:电子工程专业学生、电源电路设计初学者、希望深入了解LDO特性的工程师。 使用场景及目标:适用于希望通过仿真工具提高LDO设计技能的人群。主要目标是掌握LDO的基本工作原理,学会使用LTspice进行各种类型的仿真分析,从而优化电路设计,确保系统的稳定性和性能。 其他说明:文章不仅提供详细的仿真步骤和技术细节,还附带了作者的实际经验和常见问题解决方案,使读者能够在实践中不断改进自己的设计思路。
渝安集团员工职业发展通道设计方案.ppt
内容概要:本文详细介绍了新能源电动汽车中VCU(整车控制器)和BMS(电池管理系统)的HIL(硬件在环)仿真技术。首先阐述了整车建模的基础,包括电池、电机等关键部件的建模要点。接着分别解析了驾驶员模块、仪表模块、BCU整车控制器模块、MCU电机模块、TCU变速箱模块、BMS电池管理模块等多个子模块的功能和实现方式。最后强调了HIL仿真在电动汽车控制系统测试和优化中的重要性,特别是在降低成本和风险方面的作用。 适合人群:从事新能源汽车研发的技术人员,尤其是专注于VCU和BMS领域的工程师。 使用场景及目标:适用于需要深入了解电动汽车控制系统仿真技术的研发团队,在产品开发初期进行系统测试和优化,确保各子系统间的协同工作正常。 其他说明:文中提供了大量代码示例,帮助读者更好地理解和实践相关概念和技术细节。此外,还分享了一些实际项目中的经验和教训,如故障注入测试的具体应用场景等。
如何应对一线人员春节后的离职潮
线性代数
离职面谈表.xls
聚宽对接qmt大礼包,配备需要的全部软件:python3.9版本,qmt模拟安装包,pycharm安装包,talib包
试用期转正表.xls
招聘数据分析.xls
如何让新员工快速融入团队
内容概要:本文详细介绍了并离网逆变器的两种主要控制策略——PQ控制和V/f控制,以及无功能量发生器(SVG)和有源电力滤波器(APF)的仿真模型。对于PQ控制,文章展示了如何将功率指令转化为电流指令,并强调了电网电压定向和限幅处理的重要性。V/f控制则用于离网模式,通过调节电压和频率来维持系统的稳定。SVG主要用于无功补偿,通过实时计算无功需求进行补偿。APF则专注于谐波检测和消除,利用自适应滤波器提高效率。此外,文中还提供了多个实用的小技巧,如仿真步长设置、模式切换时的前馈补偿等。 适合人群:从事电力电子仿真研究的技术人员,尤其是对逆变器控制策略感兴趣的工程师。 使用场景及目标:适用于需要深入理解和实现逆变器控制策略的研究项目,帮助工程师优化仿真模型,提升系统性能,确保仿真结果的准确性。 其他说明:文章不仅提供了详细的代码片段,还分享了许多实践经验,有助于读者避免常见错误,提高仿真成功率。
内容概要:本文详细介绍了如何利用Carsim与Simulink进行联合仿真,通过线性二自由度模型和卡尔曼滤波(KF)来估计车辆的质心侧偏角和横摆角速度。首先搭建了联合仿真框架,Carsim提供车辆状态量,Simulink负责算法处理。文中展示了线性二自由度模型的状态方程及其参数设定,并深入探讨了KF的两种实现方式:S函数编程和Simulink内置模块。对于S函数实现,着重讲解了状态转移矩阵的动态更新以及噪声矩阵Q的调整策略,确保模型能够适应车速变化。而对于内置模块,则指出了其在灵活性方面的不足之处。此外,还讨论了联合仿真的配置要点,如数据接口同步、采样时间和信号处理等问题。 适合人群:从事车辆动力学研究、控制理论应用、自动化控制领域的工程师和技术人员。 使用场景及目标:适用于需要精确估计车辆质心侧偏角和横摆角速度的研究和开发项目,特别是在涉及ESP等主动安全系统的开发过程中。目标是提高估计精度,增强系统的鲁棒性和响应速度。 其他说明:文章提供了详细的代码片段和实践经验分享,帮助读者更好地理解和实施相关技术。建议在实际应用中根据具体需求选择合适的KF实现方式,并注意处理各种边界条件和异常情况。
档案管理[03]
内容概要:本文详细介绍了风电与储能联合调频系统的原理及其优化方法。首先解释了风电输出功率的波动性和对电网频率的影响,提出储能系统作为解决方案。文中展示了如何用Python生成风速数据并构建调频控制系统,重点讨论了PID控制器的设计以及SOC(荷电状态)管理策略。此外,还探讨了调频控制逻辑、硬件在环测试、风电功率预测模型(如LSTM)、调频效果验证方法及储能系统的物理限制等问题。最后强调了模型验证的重要性,提出了异常数据注入测试的方法。 适合人群:从事电力系统自动化、新能源发电及储能技术研发的专业人士,尤其是有一定编程基础的研究人员和技术工程师。 使用场景及目标:适用于需要理解和实施风电与储能联合调频项目的团队。主要目标是提高电网稳定性,减少风电波动带来的负面影响,同时延长储能系统的使用寿命。 其他说明:文中提供了大量实用的Python代码示例,涵盖了从数据生成到控制逻辑实现再到模型验证的全过程。对于希望深入理解风储调频系统的工作机制和技术挑战的人来说,是一份非常有价值的参考资料。
HCIA-Storage V4.5 培训教材 合集
内容概要:本文详细介绍了利用西门子S7-1200系列PLC和博途V15软件平台构建的小车自动往返控制系统。首先进行硬件组态,选择合适的CPU并配置输入输出点位,确保限位开关和急停按钮的有效接入。接着编写梯形图逻辑,实现小车在AB两点间的精确控制,采用定时器互锁机制避免电机损坏。然后设计触摸屏界面,通过WinCC创建动画效果展示小车运动状态,并设置按钮操作实现手动与自动模式切换。最后进行联合仿真实验,解决常见错误如变量地址配置不当等问题,确保系统稳定运行。 适合人群:工业自动化领域的工程师和技术人员,尤其是对PLC编程和HMI设计有一定基础的学习者。 使用场景及目标:适用于需要掌握PLC控制系统设计全流程的专业人士,帮助他们理解如何整合硬件组态、梯形图编程以及HMI开发,最终完成一个完整的自动化工程项目。 其他说明:文中提供了详细的调试经验和技巧,附带74分钟的操作录像资料,有助于读者更好地理解和实践相关知识点。
公司员工关怀工作清单
内容概要:本文详细介绍了如何利用ANSYS/LS-DYNA进行多孔延时起爆和重复起爆的仿真。首先强调了起爆点的时间线控制和材料参数设置的重要性,如使用*INITIAL_DETONATION关键字设定起爆时间和坐标,以及配置JWL方程等材料属性。接着讨论了重复起爆的具体实现方式,包括使用*CONTROL_TERMINATION配合重启动功能,确保起爆点的正确复用。此外,文章还提供了调试技巧,如检查起爆同步性和优化时间步控制,以确保仿真的准确性。最后,分享了一些实际应用中的经验和常见错误,帮助用户更好地理解和掌握这一复杂的技术。 适合人群:从事爆炸力学研究和爆破工程设计的专业人士,尤其是有一定ANSYS/LS-DYNA使用经验的工程师。 使用场景及目标:适用于需要精确控制多个起爆点时间延迟和多次起爆的应用场合,如矿山开采、隧道挖掘等领域的爆破作业仿真。目标是提高爆破效率,减少对周围环境的影响。 其他说明:文中提到的许多技术细节对于初学者来说可能会有一定的难度,因此建议从简单的单孔起爆开始练习,逐步掌握复杂的多孔延时和重复起爆技术。同时,保持良好的注释习惯有助于追踪参数修改历史,便于后续调试和维护。
内容概要:本文档详细介绍了Java面向对象编程的三大核心特性:封装、继承与多态。封装通过访问修饰符限制属性的访问权限,确保数据的安全性和完整性,如Student类中将name和age设为私有属性并通过公共方法进行访问控制。继承使得子类可以复用父类的属性和方法,减少代码冗余,如Dog类继承了Animal类的属性和方法并增加了特有的bark()方法。多态分为编译时多态(方法重载)和运行时多态(方法重写),它允许不同对象以相同接口执行不同的行为,如Shape类及其子类Circle和Rectangle通过重写getArea()方法实现了不同的面积计算逻辑,并在Main类中展示了多态的实际应用。 适合人群:具有Java编程基础的学习者或开发者,特别是对面向对象概念有初步了解但需要深入理解的人群。 使用场景及目标:①掌握Java中封装的实现机制,学会使用访问修饰符保护类成员;②理解继承的概念,能够创建父子类关系并利用继承特性提高代码复用性;③熟悉多态的应用场景,能够在实际项目中运用多态特性实现灵活的对象行为。 阅读建议:本资源侧重于理论讲解与简单示例演示,建议读者在学习过程中结合实际编程练习加深理解,同时注意对比不同特性的应用场景,以便更好地掌握面向对象编程的核心思想。