内容简介:欢迎关注公众号:【如果有需要后台回复
欢迎关注公众号:【 爱编程 】
如果有需要后台回复 2019 赠送 1T的学习资料 哦!!
本文是基于Netty4.1.36进行分析
服务端
Netty服务端的启动代码基本都是如下:
private void start() throws Exception { final EchoServerHandler serverHandler = new EchoServerHandler(); /** * NioEventLoop并不是一个纯粹的I/O线程,它除了负责I/O的读写之外 * 创建了两个NioEventLoopGroup, * 它们实际是两个独立的Reactor线程池。 * 一个用于接收客户端的TCP连接, * 另一个用于处理I/O相关的读写操作,或者执行系统Task、定时任务Task等。 */ EventLoopGroup bossGroup = new NioEventLoopGroup(); EventLoopGroup childGroup = new NioEventLoopGroup(); try { //ServerBootstrap负责初始化netty服务器,并且开始监听端口的socket请求 ServerBootstrap b = new ServerBootstrap(); b.group(bossGroup, childGroup) .channel(NioServerSocketChannel.class) .localAddress(new InetSocketAddress(port)) .childHandler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel socketChannel) throws Exception { // 为监听客户端read/write事件的Channel添加用户自定义的ChannelHandler socketChannel.pipeline().addLast(serverHandler); } }); ChannelFuture f = b.bind().sync(); f.channel().closeFuture().sync(); } catch (InterruptedException e) { e.printStackTrace(); } finally { bossGroup.shutdownGracefully().sync(); childGroup.shutdownGracefully().sync(); } }
从上图的代码可以总结为以下几个步骤:
1、创建ServerBootStrap实例
2、设置并绑定Reactor线程池:EventLoopGroup,EventLoop就是处理所有注册到本线程的Selector上面的Channel
3、设置并绑定服务端的channel
4、5、创建处理网络事件的ChannelPipeline和handler,网络时间以流的形式在其中流转,handler完成多数的功能定制:比如编解码 SSl安全认证
6、绑定并启动监听端口
7、当轮训到准备就绪的channel后,由Reactor线程:NioEventLoop执行pipline中的方法,最终调度并执行channelHandler
服务端创建时序图
ServerBootStrap引导启动服务端
它就是主要引导启动服务端,工作包括以下:
- 1.创建服务端Channel
- 2.初始化服务端Channel
- 3.将Channel注册到selector
- 4.端口绑定
1.创建服务端Channel
流程:
首先从用户代码的bind()其实就是AbstractBootstrap.bind(),然后通过 反射 工厂将用户通过b.channel(NioServerSocketChannel.class)传入的NioServerSocketChannel通过调用底层的jdk的SelectorProvider创建 channel ,同时也接着创建好对应的 ChannelPipeline 。
详情可以参考下图,自己去查看一下源码:
2.初始化服务端Channel
主要工作如下:
1)设置的option缓存到NioServerSocketChannelConfig里
2)设置的attr设置到channel里
3)保存配置的childOptions,配置的childAttrs 到ServerBootstrapAcceptor里
4)往NioSocketChannel的pipeline中添加一个 ServerBootstrapAcceptor
主要的核心源码如下:
@Override void init(Channel channel) throws Exception { final Map<ChannelOption<?>, Object> options = options0(); synchronized (options) { setChannelOptions(channel, options, logger); } final Map<AttributeKey<?>, Object> attrs = attrs0(); synchronized (attrs) { for (Entry<AttributeKey<?>, Object> e: attrs.entrySet()) { @SuppressWarnings("unchecked") AttributeKey<Object> key = (AttributeKey<Object>) e.getKey(); channel.attr(key).set(e.getValue()); } } ChannelPipeline p = channel.pipeline(); final EventLoopGroup currentChildGroup = childGroup; final ChannelHandler currentChildHandler = childHandler; final Entry<ChannelOption<?>, Object>[] currentChildOptions; final Entry<AttributeKey<?>, Object>[] currentChildAttrs; synchronized (childOptions) { currentChildOptions = childOptions.entrySet().toArray(newOptionArray(0)); } synchronized (childAttrs) { currentChildAttrs = childAttrs.entrySet().toArray(newAttrArray(0)); } p.addLast(new ChannelInitializer<Channel>() { @Override public void initChannel(final Channel ch) throws Exception { final ChannelPipeline pipeline = ch.pipeline(); ChannelHandler handler = config.handler(); if (handler != null) { pipeline.addLast(handler); } ch.eventLoop().execute(new Runnable() { @Override public void run() { pipeline.addLast(new ServerBootstrapAcceptor( ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs)); } }); } }); }
小结:
总体如上面工作流程所述。
特别地建议:查看ServerBootstrapAcceptor源码,你可以发现ServerBootstrapAcceptor在channelRead事件触发的时候(也就有客户端连接的时候),把childHandler加到childChannel Pipeline的末尾,设置childHandler的options和attrs,最后把childHandler注册进childGroup
3.将Channel注册到selector
注册过程如下图
小结:
Channel 注册过程所做的工作就是将 Channel 与对应的 EventLoop 关联。
1).每个 Channel 都会关联一个特定的 EventLoop, 并且这个 Channel 中的所有 IO 操作都是在这个 EventLoop 中执行的;
2).当关联好 Channel 和 EventLoop 后, 会继续调用底层的 Java NIO SocketChannel 的 register 方法, 将底层的 Java NIO SocketChannel 注册到指定的 selector 中.
通过这两步, 就完成了 Netty Channel 的注册过程.
4.端口绑定
端口绑定的源码流程基本如下图,详情可以还是你自己读一下源码比较好点。
小结:
其实netty端口绑定是调用 jdk的javaChannel().bind(localAddress, config.getBacklog());进行绑定,然后TCP链路建立成功,Channel激活事件,通过channelPipeline进行传播。
客户端
客户端启动的常规代码如下:
private void start() throws Exception { /** * Netty用于接收客户端请求的线程池职责如下。 * (1)接收客户端TCP连接,初始化Channel参数; * (2)将链路状态变更事件通知给ChannelPipeline */ EventLoopGroup group = new NioEventLoopGroup(); try { Bootstrap b = new Bootstrap(); b.group(group) .channel(NioSocketChannel.class) .remoteAddress(new InetSocketAddress(host,port)) .handler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel socketChannel) throws Exception { socketChannel.pipeline().addLast(new EchoClientHandler()); } }); //绑定端口 ChannelFuture f = b.connect().sync(); f.channel().closeFuture().sync(); } catch (Exception e) { group.shutdownGracefully().sync(); } }
流程:
1.用户线程创建Bootstrap实例,通过API设置创建客户端相关的参数,异步发起客户端连接。
2.创建处理客户端连接、I/O读写的Reactor线程组NioEventLoopGroup,默认为CPU内核数的2倍。
3.通过Bootstrap的ChannelFactory和用户指定的Channel类型创建用于客户端NioSocketChannel,它的功能类似于JDK NIO类库提供的SocketChannel
4.创建默认的Channel Handler Pipeline,用于调度和执行网路事件。
5.异步发起TCP连接,判断连接是否成功。如果成功,则直接将NioSocketChannel注册到多路复用器上,监听读操作位,用于数据包读取和消息发送,如果没有立即连接成功,则注册连接监听为到多路复用器,等待连接结果。
6.注册对应的网络监听状态为到多路复用器。
7.由多路复用器在I/O现场中轮询个Channel,处理连接结果。
8.如果连接成功,设置Future结果,发送连接成功事件,触发ChannelPipeline执行。
9.由ChannelPipeline调度执行系统和用户的ChannelHandler,执行逻辑。
源码调用流程如下图:
小结:
客户端是如何发起 TCP 连接的?
如下图:
特别提醒:
在AbstractChannelHandlerContext.connect()#findContextOutbound这步操作是返回的结果next其实是 头节点 ,也就是说在下一步next.invokeConnect()这里的next就是 头节点 ,所以最终是调用 HeadContext .connect()
总结
本文主要讲述netty服务端和客户端的简单工作流程。
具体服务端与客户端如何通信,以及内存管理等方面的知识下一次再写。
最后
如果对 Java 、大数据感兴趣请长按二维码关注一波,我会努力带给你们价值。觉得对你哪怕有一丁点帮助的请帮忙点个赞或者转发哦。
关注公众号 【爱编码】 ,回复 2019 有相关资料哦。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 支付宝客户端架构解析:iOS 客户端启动性能优化初探
- 自己动手做数据库客户端: BashSQL开源数据库客户端
- 支付宝客户端架构解析:Android 客户端启动速度优化之「垃圾回收」
- 客户端HTTP缓存
- 简析移动客户端安全
- 配置Hadoop集群客户端
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Cyberwar
Kathleen Hall Jamieson / Oxford University Press / 2018-10-3 / USD 16.96
The question of how Donald Trump won the 2016 election looms over his presidency. In particular, were the 78,000 voters who gave him an Electoral College victory affected by the Russian trolls and hac......一起来看看 《Cyberwar》 这本书的介绍吧!