netty tcp服务端主动断开客户端_「Netty核心技术」6-ChannelPipeline源码
ChannelPipeline是Channelhandler的容器,它负责ChannelHandler的管理和事件拦截与调度。
土话:
ChannelPipeline就是用来管理Channelhandler有增删功能。还有一些事件的拦截,交给ChannelHandler处理。
关于阅读源码的步骤,请参考这份源码阅读步骤你值得拥有
ChannelPipeline的功能
管理ChannelHandler
- addXXX:增加ChannelHandler
- get:获得ChannelHandler
- remove:移除ChannelHandler
- replace:代替ChannelHander
拦截ChannelHandler的事件,这里比较重要
从图中看
- 从Socket.read()经过ChannelHandler1,ChannelHandler2....ChannelHandlerN开始称为inbound事件。
- 从ChannelHandlerContext开始经过ChannelHandlerN,ChannelHandlerN-1,...一直到ChannelHandler1,Socket.write()称为outbound事件。
inbound事件对应ChannelInboundInvoker类
inbound事件通常由I/O线程触发,例如TCP链路建立事件,链路关闭事件,读事件,异常通知事件等。
public interface ChannelInboundInvoker { //Channel注册事件 //Channel注册成功后会执行该方法,对应的地方AbstractChannel.register0方法 ChannelInboundInvoker fireChannelRegistered(); //取消注册事件 //取消注册后调用,对应的地方AbstractChannel.deregister ChannelInboundInvoker fireChannelUnregistered(); //TCP链路建立成功,Channel激活事件,客户端与服务端建立连接 //客户端发起请求后 //服务端会从ServerBootstrapAcceptor会收到channelRead,childGroup注册一个child //对应的地方是AbstractChannel.register0 //客户端则再连接成功后对应的地方AbstractNioChannel.fulfillConnectPromise ChannelInboundInvoker fireChannelActive(); //客户端与服务端断开连接的时候调用 ChannelInboundInvoker fireChannelInactive(); //异常的通知事件 ChannelInboundInvoker fireExceptionCaught(Throwable cause); //用户自定义事件 //就是我们定义ChannelHandler的时候可以调用我们自定义的fireUserEventTriggered ChannelInboundInvoker fireUserEventTriggered(Object event); //读数据事件 //对应调用的地方是NioUnsafe.read ChannelInboundInvoker fireChannelRead(Object msg); //读操作完成 //对应调用的地方是NioUnsafe.read读完后调用 ChannelInboundInvoker fireChannelReadComplete(); //channel的可写状态变化通知事件 ChannelInboundInvoker fireChannelWritabilityChanged();}
上面的每个方法都很重要,我们要自定义ChannelHandler的时候必须要知道怎么调用这些方法。
outbound事件对应ChannelOutboundInvoker类
outbound通常是由用户主动发起的网络I/O操作,例如用户发起的连接操作,绑定操作,消息发送等操作。
public interface ChannelOutboundInvoker { //bind本地地址事件 ChannelFuture bind(SocketAddress localAddress); //连接服务端事件 ChannelFuture connect(SocketAddress remoteAddress); ChannelFuture connect(SocketAddress remoteAddress, SocketAddress localAddress); //断开连接事件 ChannelFuture disconnect(); //关闭当前channel事件 ChannelFuture close(); //取消注册事件 ChannelFuture deregister(); ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise); ChannelFuture connect(SocketAddress remoteAddress, ChannelPromise promise); ChannelFuture connect(SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise); ChannelFuture disconnect(ChannelPromise promise); ChannelFuture close(ChannelPromise promise); ChannelFuture deregister(ChannelPromise promise); //读事件 ChannelOutboundInvoker read(); //发送事件 ChannelFuture write(Object msg); ChannelFuture write(Object msg, ChannelPromise promise); //刷新事件 ChannelOutboundInvoker flush(); //写和刷新事件 ChannelFuture writeAndFlush(Object msg, ChannelPromise promise); ChannelFuture writeAndFlush(Object msg); ChannelPromise newPromise(); ChannelProgressivePromise newProgressivePromise(); ChannelFuture newSucceededFuture(); ChannelFuture newFailedFuture(Throwable cause); ChannelPromise voidPromise();}
我们扩展事件一般是在inbound事件。
核心类DefaultChannelPipeline
DefaultChannelPipeline是Netty用来管理ChannelHandler的核心类
DefaultChannelPipeline
protected DefaultChannelPipeline(Channel channel) { this.channel = ObjectUtil.checkNotNull(channel, "channel"); succeededFuture = new SucceededChannelFuture(channel, null); voidPromise = new VoidChannelPromise(channel, true); tail = new TailContext(this); head = new HeadContext(this); head.next = tail; tail.prev = head;}
分析DefaultChannelPipeline关键成员变量
- head:是现实HeadContext继承了AbstractChannelHandlerContext,AbstractChannelHandlerContext就是Channelhandler的上下文。DefaultChannelPipeline包含了很多ChannelHander,指向第一个事件
- tail:对应TailContext,指向DefaultChannelPipeline的末尾事件。
- channel:注册的channel,例如服务端对应的就是NioSockerServerChannel,客户端对应的就是NioSocketChannel。
- pendingHandlerCallbackHead:当执行完了handler的增加删除操作后调用,用来做回调处理。
- registered:AbstractChannel是否注册,一旦注册了就不会再改变了
分析AbstractChannelHandlerContext类
- AttributeMap,DefaultAttributeMap一些参数的定义Map
- ResourceLeakHint:就是用来定义做一些提示,打印一些自定义参数用的。
- ChannelHandlerContext:它代表了 ChannelHandler 和ChannelPipeline 之间的关联。接口ChannelHandlerContext 主要是对通过同一个 ChannelPipeline 关联的 ChannelHandler 之间的交互进行管理。
ChannelHandlerContext就是结合了ChannelInboundInvoker和ChannelOutboundInvoker,然后多了一些Handler的处理,比如说名称,获得ChannelHandler等等。
阅读源码知识点:
刚开始设计框架的时候,开发者也不会说设计的很完善,都是后面设计之后,慢慢抽象出来的。例如你要问我为什么要设计一个ChannelHandlerContext出来,我只能跟你说,有一些抽象方法ChannelInboundInvoker和ChannelOutboundInvoker没有必须要有一个新的接口聚合它两,并且要提供一些方法。
再来看AbstractChannelHandlerContext成员变量
- AbstractChannelHandlerContext next:头结点
- AbstractChannelHandlerContext prev:尾结点
- inBound:是否为inbound事件
- outbound:是否为outbound事件
AbstractChannelHandlerContext的结构是一个双链表
AbstractChannelHandlerContext结构
再来分析DefaultChannelHandlerContext类
final class DefaultChannelHandlerContext extends AbstractChannelHandlerContext { private final ChannelHandler handler; DefaultChannelHandlerContext( DefaultChannelPipeline pipeline, EventExecutor executor, String name, ChannelHandler handler) { super(pipeline, executor, name, isInbound(handler), isOutbound(handler)); if (handler == null) { throw new NullPointerException("handler"); } this.handler = handler; }
主要就是封装handler成一个Context
分析HeadContext类
final class HeadContext extends AbstractChannelHandlerContext implements ChannelOutboundHandler, ChannelInboundHandler
HeadContext实现了ChannelOutboundHandler,ChannelInboundHandler。上面说过outbound事件是一些网络I/O操作,例如用户发起的连接操作,绑定操作,消息发送等操作。intbound:CP链路建立事件,链路关闭事件,读事件,异常通知事件等。
分析TailContext类
final class TailContext extends AbstractChannelHandlerContext implements ChannelInboundHandler
TailContext只实现了ChannelInboundHandler,但是它的一些inbound事件都不能使用,因为HeadContext已经使用了。
@Override public void channelActive(ChannelHandlerContext ctx) throws Exception { onUnhandledInboundChannelActive(); } @Override public void channelInactive(ChannelHandlerContext ctx) throws Exception { onUnhandledInboundChannelInactive(); } @Override public void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception { onUnhandledChannelWritabilityChanged(); }
onUnhandledXXXX:就表示do noting。
小结一下,本篇讲解了
- ChannelPipeline的功能,是用来管理Channelhandler,和拦截事件请求。
- 分析了ChannelPipeline的inbound事件通常由I/O线程触发,例如TCP链路建立事件,链路关闭事件,读事件,异常通知事件等。outbound通常是由用户主动发起的网络I/O操作,例如用户发起的连接操作,绑定操作,消息发送等操作。
- 核心类DefaultChannelPipeline的功能
- 核心类DefaultChannelPipeline的成员变量AbstractChannelHandlerContext是一个双向链表,它用来保存Channelhandler
- 核心类DefaultChannelPipeline的成员变量,HeadContext指向AbstractChannelHandlerContext的头部,TailContext指向AbstractChannelHandlerContext尾部。
下篇讲解ChannelPipeline源码解析二,主要分析DefaultChannelPipeline中的核心方法。
建议阅读
「Netty核心技术」5-客户端启动
「Netty核心技术」4-服务端启动
「Netty核心技术」3-AbstractBootStrap
「Netty核心技术」2-HelloWorld
「Netty核心技术」1-序言
netty tcp服务端主动断开客户端_「Netty核心技术」6-ChannelPipeline源码相关推荐
- netty tcp服务端主动断开客户端_【Netty】服务端和客户端
欢迎关注公众号:[爱编程] 如果有需要后台回复2019赠送1T的学习资料哦!! 本文是基于Netty4.1.36进行分析 服务端 Netty服务端的启动代码基本都是如下: private void s ...
- php守护进程内存溢出,$serv-close($fd); 服务端主动断开客户端有问题!
'core' => array( 'reactor_num' => 2, // 线程数. 一般设置为CPU核数的1-4倍 'worker_num' => 16, // 工作进程数量. ...
- netty获取玩家chanel_基于netty的TCP服务端如何给客户端发送消息,但是如何拿到客户端连接时的SocketChannel呢,菜鸟求助?...
1.思路1 每个客户端连接时的SocketChannel保存在会话类sessionManager中的sessionIdMap中 问题: 1.客户端连接时确实将SocketChannel保存在会话类se ...
- springboot实现SSE服务端主动向客户端推送数据,java服务端向客户端推送数据,kotlin模拟客户端向服务端推送数据
SSE服务端推送 服务器向浏览器推送信息,除了 WebSocket,还有一种方法:Server-Sent Events(以下简称 SSE).本文介绍它的用法. 在很多业务场景中,会涉及到服务端向客户端 ...
- ssm配置socket_ssm框架中集成websocket实现服务端主动向客户端发送消息
找了很多配置文档及实例说明,也还是没能成功,最终在csdn博客中发现了基于stomp的消息推送的文章, 下面整理自csdn博客,https://blog.csdn.net/u013627689/art ...
- tcp 服务端如何判断客户端断开连接
最近在做一个服务器端程序,C/S结构.功能方面比较简单就是client端与server端建立连接,然后发送消息给server.我在server端会使用专门的线程处理一条socket连接.这就涉及到一个 ...
- netty 服务端主动向客户端发信息
在使用netty时,有时候会和客户端保持长链接,这个时候服务端既可以接受客户端消息也可以主动发送消息给服务端.我们只需要在服务端保存客户端的ChannelHandlerContext对象,必要的时候通 ...
- QT 之 TCP 服务端 连接 多客户端 处理学习
自学QT中, 在此记录一下TCP多链接的方法. 跟着 "Qt Creator快速入门" 学了一段时间了,刚接触网络编程, 例子中仅仅简单的 用 客户端 连接了一下 服务端, 然后 ...
- netty既做服务端又做客户端_网易新闻客户端广告怎么做
网易新闻客户端广告怎么投放? l 网易新闻客户端是网易公司为亿万用户打造的一款移动资讯类APP. l 敢于评论社会新闻的人群必定是一群有质量的人群. l 以"激发每个人思考,态度就在你 ...
最新文章
- Linux 环境变量配置
- No architectures to compile for (ONLY_ACTIVE_ARCH=YES, active arch=arm64, VALID_ARCHS=armv7 armv7s)
- 由华为提供现网商用平台的IPTV业务亮相深圳文博会
- linux dup用法,Unix_Linux
- 普通行列转换(交叉表,横表变列表)
- strtus2改成springboot_ssh框架使用springBoot升级迁移替换Struts2
- Qt工作笔记-如何正确使用QXmlStreamReader(学会利用错误提示)
- 【写作技巧】绪论写作要点
- 【javascript】基于javascript的小时钟
- 由First表和Follow表得到LL1表(笔记)
- Linux使用docker安装RabbitMQ一站式教程【图文教程】
- dialog下textarea滚动条不显示
- [足式机器人]Part3机构运动微分几何学分析与综合Ch01-1 平面运动微分几何学——【读书笔记】
- java web生僻字传值_生僻字歌,它们的含义和出处都在这里
- 计算机开机检测dhcp,电脑开机显示dhcp是什么意思
- PostgreSQL-Docker创建PostgreSQL数据库并导入矢量数据
- 2018年淘宝新店开业怎么引流量
- Python日常小技巧(持续更新中)
- 【千锋Python2205班9.29笔记-day09-字符串(一阶段)】
- Mac Scrcpy无线连接