netty获取玩家chanel_我是怎样阅读 Netty Channel 源码的
Channel 功能说明
我在使用 ServerBootstrap 来创建服务的时候通过 channel(NioServerSocketChannel.class) 来设置 Channel, 那么 Channel 的主要作用是什么呢?
在分析 Channel 之前, 需要先弄懂 NioServerSocketChannel 类, 它的功能对于 JDK NIO 类库中的
ServerSocketChannel 类, 它是用来监听TCP连接的(并不管读写).
而 NioServerSocketChannel 最主要就是实现 Channel 接口. Channel 接口, 采用 Facade 模式进行统一封装, 将网络的读、写, 客户端发起连接, 主动关闭连接, 链路关闭, 获取通信双方的网络地址等.
Channel 接口下有一个重要的抽象类 AbstractChannel, 一些公共的基础方法都在这个抽象类中实现, 而特定一些功能, 都可以通过各个不同的实现类去实现, 这样最大程度的实现功能和接口的重用.
为什么不实用 JDK NIO 原生的 Channel 而要另起炉灶呢?
JDK SocketChannel 和 ServerSocketChannel 没有统一的 Channel.
JDK 的 SocketChannel 和 ServerSocketChannel 的主要职责就是网络 IO 操作, 由于他们的 SPI 类接口, 由具体的虚拟机厂家提供, 所以通过继承 SPI 功能类来扩展其功能的难度很大; SocketChannel 和 ServerSocketChannel 抽象类, 其工作量和重新开发一个新的 Channel 功能类是差不多的.
Netty 的 Channel 需要能够跟 Netty 的整体架构融合在一起, 例如 IO 模型、基于 ChannelPipeline 的定制模型, 以及基于元数据描述配置化的 TCP 参数等, 这些 JDK 的 SocketChannel 和 ServerSocketChannel 都没有提供, 需要重新封装.
自定义的 Channel, 功能实现更加灵活.
Channel 方法介绍
Channel read(): 从当前的 Channel 中读取数据到第一个 inbound 缓冲区中, 如果数据被成功读取, 触发 ChannelHandler.channelRead(ChannelHandlerContext, Object) 事件.
读取操作 API 调用完成之后, 紧接着会触发 ChannelHandler.channelReadComplete(ChannelHandlerContext) 事件, 这样业务的 ChannelHandler 可以决定是否需要继承读取数据. 如果已经有读操作请求被挂起, 则后续的读操作会被忽略.
ChannelFuture write(Object): 请求将当前的 msg 通过 ChannelPipeline 写入到目标 Channel 中. 注意, write 操作只是将消息存入到消息发送环数组中, 并没有真正被发送, 只有调用 flush 操作才会被写入到 Channel 中, 发送给对方.
ChannelFuture write(Object, ChannelPromise): 功能与 Channel read() 相同, 但是携带了 ChannelPromise 参数负责设置写入操作的结果.
ChannelFuture writeAndFlush(Objec, ChannelPromise): 与上面方法功能类似, 不同之处在于它会将消息写入 Channel 中发送, 等价于单独调用 write 和 flush 操作的组合.
Channel flush(): 将之前写入到发送环形中的消息全部写入到目标 Channel 中, 发送给通信对方.
ChannelFuture close(ChannelPromise): 主动关闭当前连接, 通过 ChannelPromise 设置操作结果并执行结果通知, 无论操作是否成功, 都可以通过 ChannelPromise 获取操作结果. 该操作会级联触发 ChannelPipeline 中所有 ChannelHandler 的 ChannelHandler.close(ChannelHandlerContext, ChannelPromise) 事件.
ChannelFuture disconnect(ChannelPromise): 请求断开与远程通信对端的连接并使用 ChannelPromise 来获取操作结果的通知消息. 该方法会级联触发 ChannelHandler.disconnect(ChannelHandlerContext, ChannelPromise) 事件.
ChannelFuture connect(SocketAddress remoteAddress): 客户端使用指定的服务端地址 remoteAddress 发起连接请求, 如果连接因为应答超时而失败, ChannelFuture 中的操作结果就是 ConnectTimeoutException 异常; 如果连接被拒绝, 操作结果为 ConnectException. 该方法会级联触发 ChannelHandler.connect(ChannelHandlerContext, SocketAddress, SocketAddress, ChannelPromise) 事件.
ChannelFuture bind(SocketAddress localAddress): 绑定指定的本地 Socket 地址 localAddress, 该方法会级联触发 ChannelHandler.bind(ChannelHandlerContext, SocketAddress, ChannelPromise) 事件.
ChannelConfig config(): 获取当前 Channel 的配置信息, 例如 CONNECT_TIMEOUT_MILLIS.
boolean isOpen(): 判断当前 Channel 是否已经打开.
boolean isRegistered(): 判断当前 Channel 是否已经注册到 EventLoop 上.
boolean isActive(): 判断当前 Channel 是否已经处于激活状态.
ChannelMetadata metadata(): 获取当前 Channel 的元数据描述信息, 包括 TCP 参数配置等.
SocketAddress localAddress(): 获取当前 Channel 的本地绑定地址.
SocketAddress remoteAddress(): 获取当前 Channel 通信的远程 Socket 地址.
eventLoop(): Channel 需要注册到 EventLoop 的多路复用器上, 用于处理 IO 事件, 通过 eventLoop() 方法可以获取到 Channel 上注册的 EventLoop. EventLoop 本质上就是处理网络读写事件的 Reactor 线程. 也可以用来执行定时任务和用户自定义 NioTask 等任务.
id(): 它返回 ChannelId 对象, 是 Channel 的唯一标识, 它的可能生成策略如下:
机器的 MAC 地址(EUI-48 或 EUI-64) 等可以代表全局唯一的信息;
当前的进程 ID;
当前系统的毫秒-- System.currentTimeMillis();
当前系统的纳秒-- System.nanoTime();
32 位的随机整数;
32 位自增的序列数.
AbstractChannel 源码分析
AstractChannel 聚合了所有 Channel 使用到的对象, 由 AbstractChannel 提供初始化和统一封装, 如果功能和具体子类相关, 则定义成抽象方法由子类具体实现.
static final ClosedChannelException CLOSED_CHANNEL_EXCEPTION = new ClosedChannelException();
static final NotYetConnectedException NOT_YET_CONNECTED_EXCEPTION = new NotYetConnectedException();
static {
CLOSED_CHANNEL_EXCEPTION.setStackTrace(EmptyArrays.EMPTY_STACK_TRACE);
NOT_YET_CONNECTED_EXCEPTION.setStackTrace(EmptyArrays.EMPTY_STACK_TRACE);
}
private MessageSizeEstimator.Handle estimatorHandle;
private final Channel parent;
private final ChannelId id = DefaultChannelId.newInstance();
private final Unsafe unsafe;
private final DefaultChannelPipeline pipeline;
private final ChannelFuture succeededFuture = new SucceededChannelFuture(this, null);
private final VoidChannelPromise voidPromise = new VoidChannelPromise(this, true);
private final VoidChannelPromise unsafeVoidPromise = new VoidChannelPromise(this, false);
private final CloseFuture closeFuture = new CloseFuture(this);
....
protected AbstractChannel(Channel parent, EventLoop eventLoop) {
this.parent = parent;
this.eventLoop = validate(eventLoop);
unsafe = newUnsafe();
pipeline = new DefaultChannelPipeline(this);
}
每一个 Channel 中包含一个 ChannelPipeline. 在 AbstractChannel 的构造方法中初始化. AbstractChannel 也提供了一些公共 API 的具体实现, 例如 localAddress() 和 remoteAddress().
当 Channel 进行 IO 操作时会产生对应的 IO 事件, 然后驱动事件在 ChannelPipeline 中传播, 由对应的 ChannelHandler 对事件进行拦截和处理, 不关心的事件可以直接忽略.
网络 IO 操作直接调用 DefaultChannelPipeline 的相关方法, 由 DefaultChannelPipeline 中对应的 ChannelHandler 进行具体逻辑的处理.
netty获取玩家chanel_我是怎样阅读 Netty Channel 源码的相关推荐
- netty获取玩家chanel_基于netty的TCP服务端如何给客户端发送消息,但是如何拿到客户端连接时的SocketChannel呢,菜鸟求助?...
1.思路1 每个客户端连接时的SocketChannel保存在会话类sessionManager中的sessionIdMap中 问题: 1.客户端连接时确实将SocketChannel保存在会话类se ...
- Netty网络框架学习笔记-16(心跳(heartbeat)服务源码分析)
Netty网络框架学习笔记-16(心跳(heartbeat)服务源码分析_2020.06.25) 前言: Netty 作为一个网络框架,提供了诸多功能,比如编码解码等,Netty 还提供了非常重要的一 ...
- 封装成jar包_通用源码阅读指导mybatis源码详解:io包
io包 io包即输入/输出包,负责完成 MyBatis中与输入/输出相关的操作. 说到输入/输出,首先想到的就是对磁盘文件的读写.在 MyBatis的工作中,与磁盘文件的交互主要是对 xml配置文件的 ...
- golangsha1解码_如何阅读Golang的源码?
Go 的源码在安装包的 src/ 目录下.怎么看它的源码呢?直接看吧!没人教的情况下,只能自己撸了.当然,这种内容一般也不会有人教. 怎么撸? Go 源码中,应该可分为与语言息息相关的部分,和官方提供 ...
- Android --- IjkPlayer 阅读native层源码之解码成功后的音频数据如何发送回Android播放(九)
整章目录:Android------- IjkPlayer 源码学习目录 本篇会有很多源代码,请注意阅读每行代码上面的注释. 本篇介绍的主要内容为上图红框圈起部分: 在前面介绍了如何将一个AvPack ...
- Android ---- Ijkplayer阅读native层源码之IjkMediaPlayer_prepareAsync(五)
整章目录:Android------- IjkPlayer 源码学习目录 本篇会有很多源代码,请注意阅读每行代码上面的注释. 本篇介绍的主要内容为上图红框圈起部分: IjkMediaPlayer_pr ...
- 以太坊源码阅读5——POW源码分析
以太坊源码阅读5--POW源码分析 介绍 POW,proof of work,即工作量证明,是著名公bitcoin所采用的共识算法.简单来说,pow就是一个证明,由矿工使用算力进行计算(挖矿),竞争记 ...
- rust墙壁升级点什么_分享:如何在阅读Rust项目源码中学习
今天做了一个Substrate相关的小分享,公开出来. 因为我平时也比较忙,昨天才选定了本次分享的主题,准备比较仓促,细节可能不是很充足,但分享的目的也是给大家提供一个学习的思路,更多的细节大家可以在 ...
- 获取网络时间并刷新本地时间(源码2)
因为上次那个获取网络时间失效了(使用的是37端口),获取网络时间并刷新本地时间(源码1) 所以网上又找了一份代码,使用的是123端口,虽然没有测试成功,这里也做下记录,估计是本机环境问题,过两天再进行 ...
最新文章
- leetcoder reverse polish notation解题笔记
- html表格自动换行
- print 和 printf 和 println
- oracle 表空间热备份,oracle对表空间的热备
- vs html自动对齐,vscode esLint 保存时 自动对齐
- bar图设置距离 python_python画图设置坐标轴的位置及角度及设置colorbar
- chromium浏览器开发系列第五篇:Debugging with WinDBG
- 2017.9.5 组合数学 思考记录
- 悬浮球不用权限_Android 实现无需权限的悬浮球效果,可适配至Android 10
- 3.2 Zend_Db_Select
- 计算机网络po3代表的意思,计算机系统与网络技术中常用的单词缩写的意思.pdf...
- movmedian函数matlab,MEDIAN函数用法及实例
- 基于51单片机的超声波测距
- 《物联网技术》课程笔记——第一章 物联网概述
- 小米 2021 秋招面试总结
- 洛谷P3387 【模板】缩点 题解
- 发光二极管限流电阻(学习笔记)
- AES加密 C++调用Crypto++加密库 例子
- clob类型字段最大存储长度_Oracle的CLOB大数据字段类型
- 【Linux】vi编辑器中:wq 、:wq!、:x、:q、:q!的详细区别