netty服务端启动总结

一、基础校验

  • 1.首先校验是否上传了group,也就是我们的nioeventloop线程池
  • 2.其次在看channelFactory是否为空,我们通过channel方法设置我们的服务端channel的class类型
  • 3.检测childHandler是否存在,当我们服务端接收到客户端连接之后,会再建立一个channel保持与客户端的通信。
    通信的处理则通过childChannel
  • 4.检测是否存在childgroup,对于服务端来说group主要是处理客户端的连接请求,而childgroup则是主要处理与客户端的读写事件。
    如果我们未填写,则将group赋值给childgroup。这有可能导致 我们与客户端通信如果存在阻塞操作,而该channel又恰好
    绑定在服务端监听客户端链接的nioeventloop上,这会到连接事件超时或者阻塞
  • 5.判断我们是否设置我们监听地址:localAddress

二、实例化channel

  • 1.一般是NioServerSocketChannel的class的实例化,会调用其构造函数
  • 2.构造函数先是获取SelectorProvider,其根据os的不同底层实现也不同
  • 3.然后通过该SelectorProvider生产一个对应的channel
  • 4.然后给当前的channel设置parent为null,设置一个id,unsafe(不是jdk的unsfae)和pipeline
  • 5.pipeLine会设置其channel,tail和head链表,还有voidPromise以及succeededFuture
  • 6.该channel默认携带的readInterestOp是read事件
  • 7.给channel设置为非阻塞
  • 8.设置该channel的config,会从我们的channel中获取javaSocket也就是ServerSocket,同时设置AdaptiveRecvByteBufAllocator
    因为我们服务端channel一般只是处理链接不发送消息 所以我们这边没有设置MaxBytesPerGatheringWrite
  • 9.AdaptiveRecvByteBufAllocator设置了buffer的最大值(默认65536byte),最小值(默认64byte),初始值(默认1025byte),以及每个消息循环读取的最大次数
  • 10.其中每个消息最大循环读取次数是从channel的meta里面获取defaultMaxMessagesPerRead得到的

三、初始化channel

  • 1.将我们代码里面设置的channelOption,即设置到channelConfig的属性里面
  • 2.给channel设置key-value属性,这样的话我们可以通过该channel传递一些我们需要的数据
  • 3.添加了一个ChannelInitializer,而addLast这个方法主要的逻辑是给当前的handler和group包装成
    一个HandlerContext,默认的group为空,如果我们设置了不为空则执行这个handler就从group获取executor执行
  • 4.将当前HandlerContext加入到链表中,然后判断是否还未注册,是否是外部线程来执行逻辑
  • 5.如果还未注册则设置当前的HandlerContext为pending状态,并添加一个任务到pendingHandlerCallbackHead链表
    ,等到注册成功后执行该链表任务,其任务主要逻辑就是调用handlerAdded方法然后设置handlerContext为completed状态
  • 6.如果是外部线程则将第五步骤包装成一个任务放入队列,由loop线程自己调度
  • 7,如果就是当前线程且channel已经注册了则直接调用handlerAdded方法,设置completed标识
  • 8.对于remove也是相似操作先从handlerContext链表中剔除,再执行handlerRemoved,然后设置removed标识
  • 9.对于默认的ChannelInitializer其主要是将我们先前配置的handler(注意不是childhandler)加入到pipeline
    并且添加了一个任务放入到队列中,该任务主要就是添加ServerBootstrapAcceptor,其会专门处理连接请求,获取客户端传递过来的
    channel,给该channel添加childHandler,并且将该childchannel注册到我们childGroup上的一个loop线程上。

四、注册channel

  • 1.从group中拿一个nioeventloop,将我们的服务端channel注册到上面。

  • 2.获取loop的方式又两种一种是:Math.abs(idx.getAndIncrement() % executors.length),还有一个是
    idx.getAndIncrement() & executors.length - 1

  • 3.然后将channel和loop包装成DefaultChannelPromise,并从channel中获取unsafe调用其register方法进行实际注册

  • 4.然后判断当前线程是否和loop中的线程一致,如果不一致则将注册方法报过程一个任务放入到loop的任务队列执行然后直接返回promise

  • 5.具体的注册则是先设置该promise不可以取消,如果设置失败再检测channel是否open,不open则关闭

  • 6.将当前的channel(不是netty的nioServerSocketChannel,是jdk的serverSocketChannel)注册到我们loop中的selector上,携带我们当前的nioServerSocketChannel初始化注册感兴趣的事件=0,即对任何事件都不敢兴趣

  • 7.注册成功之后返回的selectionKey,是一个token标识。我们可以通过他获取该channel发生的事件等等。

  • 8.然后我们invokeHandlerAddedIfNeeded,因为我们在未注册成功前就设置了handlerPedding状态 需要在注册成功之后执行handlerAdded(我们的ChannelInitializer的initChannel会在handlerAdded方法调用结束后调用,该方法主要就是执行initChannel然后把ChannelInitializer从HandlerContext链表中删除,同时我们在channelRegistered也会尝试判断是否已经调用了如果没有则也会调用initChannel)

  • 9.然后在整个pipeline里面传播ChannelRegistered事件,即从head开始传递到tail,其中还会判断当前的handler是否已经是added状态不是的话跳过寻找下一个,是的话就执行channelRegistered方法

  • 10.然后再判断当前channel是否已经Active(这里active的条件是注册然后被连接了),如果已经Active且是第一次则再激活整个通道的ChannelActive事件,
    对于重复注册的channel则会判断是已经开启autoread,如果开启就直接执行beginRead,不会执行ChannelActive

  • 11.ChannelActive是从head传播到tail,传播完成执行开始channel.read(),实际上就是tail的read方法,最终调用调用到head的beginRead()

  • 12.beginRead:该方法主要是检测SelectionKey是否有效,然后设置readPending=true,注册我们该channel的感兴趣事件,我们初始化都是注册0,但是不同的netty的channel 会再初始的时候携带自己感兴趣的事件如accept(服务端)或者read(客户端)

  • 13.注意再注册chanel这个方法里面的isActive主要是 判断客户端传递到服务端的channel是否已经激活,因为该channel不需要绑定,所以可以直接激活 而对于客户端的channel或者服务端的channel都是再绑定之后再激活

五、开始绑定监听端口

  • 1.首先检测一个情况:如果套接字未绑定到通配符地址,则非root用户无法接收广播数据包。无论如何,根据请求绑定到非通配符地址(/127.0.0.1:8080)。
  • 2.检测是已经激活
  • 3.开始绑定监听端口,绑定时候传递了我们的backLog,这个是完全队列的大小
  • 4.如果是第一次激活则调用fireChannelActive方法。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,753评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,668评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,090评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,010评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,054评论 6 395
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,806评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,484评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,380评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,873评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,021评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,158评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,838评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,499评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,044评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,159评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,449评论 3 374
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,136评论 2 356

推荐阅读更多精彩内容