前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Netty源码分析之服务端启动

Netty源码分析之服务端启动

作者头像
博文视点Broadview
发布2023-04-04 11:03:33
3370
发布2023-04-04 11:03:33
举报
文章被收录于专栏:博文视点Broadview

👆点击“博文视点Broadview”,获取更多书讯

Netty在服务端启动过程中是如何绑定端口、启动服务的呢?

在启动服务的过程中,我们可以顺势了解到Netty各大核心组件。

本文暂时不会详细描述这些组件,先简单介绍一下各大组件是如何协同工作、一起构建Netty核心的。

01

服务端启动示例

我们写了一个比较完整的服务端启动例子,绑定在8888端口,使用NIO模式。

代码语言:javascript
复制
public final class SimpleServer {
    public static void main(String[] args) {        EventLoopGroup bossGroup = new NioEventLoopGroup();        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {            ServerBootstrap b = new ServerBootstrap();            b.group(bossGroup, workerGroup)                    .channel(NioServerSocketChannel.class)                    .handler(new SimpleServerHandler())                    .childHandler(new ChannelInitializer<SocketChannel>() {                        @Override                        public void initChannel(SocketChannel ch) {                        }                    });
            ChannelFuture f = b.bind(8888).sync();
            f.channel().closeFuture().sync();        } finally {            bossGroup.shutdownGracefully();            workerGroup.shutdownGracefully();        }    }
    private static class SimpleServerHandler extends ChannelInboundHandlerAdapter {        @Override        public void channelActive(ChannelHandlerContext ctx) {            System.out.println("channelActive");        }
        @Override        public void channelRegistered(ChannelHandlerContext ctx) {            System.out.println("channelRegistered");        }

        @Override        public void handlerAdded(ChannelHandlerContext ctx) {            System.out.println("handlerAdded");        }    }}

 下面来回顾一下每个方法的作用。

1. EventLoopGroup:服务端的线程模型外观类。从字面意思可以了解到,Netty的线程模型是事件驱动型的,也就是说,这个线程要做的事情就是不停地检测IO事件、处理IO事件、执行任务,不断重复这三个步骤。

2. ServerBootstrap:服务端的一个启动辅助类。通过给它设置一系列参数来绑定端口启动服务。

3. .group(bossGroup, workerGroup):设置服务端的线程模型。读者可以先想象一下:在一个工厂里,我们需要两种类型的人干活,一种是老板,一种是工人。老板负责从外面接活,把接到的活分配给工人。放到这里,bossGroup的作用就是不断地接收新的连接,将新连接交给workerGroup来处理。

4. .channel(NioServerSocketChannel.class):设置服务员的IO类型为NIO。Netty通过指定Channel的类型来指定IO类型。Channel在Netty里是一大核心概念,可以理解为,一个Channel就是一个连接或者一个服务端bind动作,后面会细讲。

5. .handler(new SimpleServerHandler():表示在服务端启动过程中,需要经过哪些流程。这里SimpleServerHandler最终的顶层接口为ChannelHandler,是Netty的一大核心概念,表示数据流经过的处理器,可以理解为流水线上的每一道关卡。

6. .childHandler(new ChannelInitializer<SocketChannel>)...:使用过Netty的读者应该知道,这里的方法体主要用于设置一系列Handler来处理每个连接的数据,也就是上面所说的,老板接到一个活之后,告诉每个工人这个活的固定步骤。

7. ChannelFuture f = b.bind(8888).sync():绑定端口同步等待。这里就是真正的启动过程了,绑定端口8888,等服务端启动完毕,才会进入下一行代码。

8. f.channel().closeFuture().sync():等待服务端关闭端口绑定,这里的作用其实是让程序不会退出。

9. bossGroup.shutdownGracefully()和workerGroup.shutdownGracefully():关闭两组事件循环,关闭之后,main方法就结束了。

上述代码可以很轻松地在本地运行,最终控制台的输出如下。

代码语言:javascript
复制
handlerAddedchannelRegisteredchannelActive

为什么控制台会按顺序输出这些字符,接下来我们就深入细节一探究竟。

02

服务端启动的核心步骤

我们通过以上示例代码来理一理服务端启动的基本流程。

在上面的示例代码中,我们是通过ServerBootstrap这个辅助类来实现服务端启动的,给这个启动类设置一些参数,然后通过它的外观接口来实现启动。重点落在下面这行代码上。

代码语言:javascript
复制
b.bind(8888).sync();

【提示】我们刚开始看源码时,在对细节没那么清楚的情况下可以借助IDE的Debug功能,单步执行,以确定程序运行的入口。

我们跟进到bind()方法。

代码语言:javascript
复制
ServerBootstrap.java
public ChannelFuture bind(int inetPort) {    return bind(new InetSocketAddress(inetPort));}

通过端口号创建一个InetSocketAddress对象,然后继续调用重载方法bind()。

代码语言:javascript
复制
ServerBootstrap.java
public ChannelFuture bind(SocketAddress localAddress) {    validate();    if (localAddress == null) {        throw new NullPointerException("localAddress");    }    return doBind(localAddress);}

validate()验证服务启动需要的必要参数,然后调用doBind()。

代码语言:javascript
复制
ServerBootstrap.java
private ChannelFuture doBind(final SocketAddress localAddress) {    //...    final ChannelFuture regFuture = initAndRegister();    //...    final Channel channel = regFuture.channel();    //...    doBind0(regFuture, channel, localAddress, promise);    //...    return promise;}

在这里,笔者减掉了细枝末节,专注于核心方法,分别为initAndRegister()和doBind0()。

从方法名我们已经可以略窥一二,init代表初始化,register代表注册,bind代表绑定端口。联系NIO开发的基本流程,可能是把某个东西初始化之后注册到Selector上,最后bind像是在本地绑定端口号。

带着这些猜测,我们深入分析下去。

我们先来看一下initAndRegister()方法。

代码语言:javascript
复制
AbstractBootstrap.java
final ChannelFuture initAndRegister() {    Channel channel = null;    //...     // 1. 创建服务端 Channel    channel = channelFactory.newChannel();    //...    // 2. 初始化服务端 Channel    init(channel);    //...    // 3. 注册服务端 Channel    ChannelFuture regFuture = config().group().register(channel);    //...    return regFuture;}

同样地,笔者略去了其他细节,专注于骨干代码。initAndRegister()中的3个主要方法与doBind0()方法一起组合成了服务端启动的4个过程。

1. 创建服务端Channel。

2. 初始化服务端Channel。

3. 注册服务端Channel。

4. 绑定服务端端口。

这4个过程的详细分析写在《跟闪电侠学 Netty:Netty 即时聊天实战与底层原理》一书中,大家可以阅读这本书继续学习哦~~

本书上篇通过一个即时聊天的例子,让读者能够系统地使用一遍Netty,全面掌握Netty的知识点;下篇通过对源码的层层剖析,让读者能够掌握Netty底层原理,知其然并知其所以然,从而编写出高性能网络应用程序。

上篇 入门实战

在入门实战篇中,读者跟随笔者实践完这个即时聊天系统后,能够学会如何使用Netty完成最基本的网络通信程序,可以掌握以下知识点:

1. 如何启动服务端?

2. 如何启动客户端?

3. 如何设计长连自定义协议?

4. 拆包/粘包原理与实践。

5. 如何实现自定义编解码。

6. 如何使用Pipeline与ChannelHandler?

7. 心跳与空闲检测的方法。

8. 如何性能调优?

本篇通俗易懂,可一口气读完,让你一周内进入实战

下篇 源码分析

在源码分析篇中,笔者从用户视角出发,环环相扣,带领读者逐个攻破Netty底层原理,掌握以下知识点:

1. 服务端启动流程:ServerBootstrap外观,创建NioServerSocketChannel,初始化,注册Selector,绑定端口,接收新连接。

2. 高并发线程模型:Netty无锁化串行设计,精心设计的Reactor线程模型榨干CPU、打满网卡、让应用程序性能爆表的底层原理。

3. 新连接接入流程:Boss Reactor线程,监测新连接,创建NioSocketChannel,IO线程分配,Selector注册事件。

4. 解码原理:解码顶层抽象,定长解码器,行解码器,分隔符解码器,基于长度域解码器全面分析。

5. 事件传播机制脉络:大动脉Pipeline,处理器ChannelHandler,Inbound和Outbound事件传播与异常传播的原理,编码原理。

6. writeAndFlush流程:深入了解使用最频繁的writeAndFlush的底层原理,避免踩坑。

适读人群

本书适合以下三类人群:

1. 如果你听说过或简单使用过Netty,想全面系统地学习Netty,并掌握一些性能调优方法,本书的入门实战篇可以帮助你达成这个目标。

2. 如果你深度使用过Netty,想深入了解Netty的底层设计,编写出更灵活高效的网络通信程序,本书的源码分析篇可以帮助你达成这个目标。

3. 如果你从未读过开源框架源码,本书将是你的第一本源码指导书,阅读优秀的开源软件源码可以助你写出更优美的程序。读源码并不难,难的是迈出这一小步,之后就能通往更广阔的空间。

本书推荐使用方式

01. 按章节顺序把入门实战篇的代码一章章敲出来,在没有掌握前一章节的知识点之前,建议不要跳跃学习。

02. 入门实战篇学完之后,合上书本,把本书即时聊天系统的代码再整体敲若干遍,敲的过程中可能会发现自己有遗忘知识点,这个时候可能需要不断翻阅书本,没有关系,翻阅就好了。

03. 确保最后一次实现本书的即时聊天系统的例子是没有翻阅书本的,是完全自行实现的,之后进入源码分析篇的学习。

04. 针对源码分析篇,建议读者按章节顺序来学习,不要跳跃,不要图快,每一步都要扎实。

05. 在源码学习的过程中,先跟随书本,对照源码,把对应章节的流程过一遍,每个章节学完之后,建议花较多的时间进行调试和阅读,确保掌握了前一章节的内容之后再进行下一章的学习。

京东限时立减50,快快扫码抢购吧!

发布:刘恩惠

审核:陈歆懿

代码语言:javascript
复制
 如果喜欢本文欢迎 在看丨留言丨分享至朋友圈 三连
 热文推荐  
我jio得,有望过上钢铁侠一样的生活了!
书单 | 春节假期,我想把这几本书带回家!
2023十大科技趋势(达摩院发布)
手把手教你编写Node.js模块


▼点击阅读原文,了解本书详情~
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-01-17,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 博文视点Broadview 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档