netty启动流程,netty 端口复用
目录
绑定端口我们继续跟第一小节的最初的多宾()方法第二步,获得引导重点关注下多宾(本地地址)方法最终会走到这一步,pipeline.fireChannelActive()章节总结前文传送门:Netty启动流程注册多路复用源码解析
绑定端口
上一小节我们学习了引导注册在选择器的步骤,仅仅做了注册但并没有监听事件,事件是如何监听的呢?
我们继续跟第一小节的最初的doBind()方法
专用信道未来数据绑定(最终SocketAddress localAddress) { //初始化并注册(1)最终通道future regFuture=init Andre register();//获得通道(2)最终通道通道=regfuture。channel();if (regFuture.cause()!=null){ return regFuture;} if(regfuture。isdone()){渠道承诺承诺=渠道。new promise();//绑定(3) doBind0(regFuture,channel,localAddress,promise);回报承诺;} else { //去除非关键代码回报承诺;}}上一小节跟完了initAndRegister()方法,我们继续往下走:
第二步, 获得channel
最终通道Channel=regfuture。channel();通过未来频道的频道()方法获得了我们刚刚注册的NioServerSocketChannel,拿到这个引导我们跟到第三步,绑定
跟进方法doBind0(regFuture,channel,localAddress,promise):
private static void dobind 0(final Channel future regFuture,final Channel channel,final SocketAddress localAddress,final Channel promise promise){ Channel。事件循环().execute(new Runnable(){ @ Override public void run(){ if(reg future。is success()){//绑定端口channel.bind(本地地址,承诺).addListener(ChannelFutureListener .CLOSE _ ON _ FAILURE);} else {承诺。设置失败(regfuture。cause());} } });}最终会走到信道绑定(本地地址,承诺)这个方法当中
继续跟,会走到抽象频道的绑定()方法中:
公共通道未来绑定(套接字地址本地地址,通道承诺承诺){ //通过管道绑定端口返回pipeline.bind(本地地址,承诺);}这里的管道就是引导初始化创建的管道,管道是事件传输通道,这里我们暂不跟传输过程,我们只需知道最后这个方法走到了抽象频道的绑定()方法
跟到抽象频道的绑定()方法:
public final void bind(最终套接字地址本地地址,最终通道承诺承诺){ //代码省略//
端口绑定之前不是active, 返回false boolean wasActive = isActive(); try { //做jdk底层的绑定 doBind(localAddress); } catch (Throwable t) { //省略 return; } //端口绑定之前不是active, 端口绑定之后变成active了 if (!wasActive && isActive()) { invokeLater(new Runnable() { @Override public void run() { pipeline.fireChannelActive(); } }); } safeSetSuccess(promise);}
重点关注下doBind(localAddress)方法
跟到NioSeverSocketChannel的doBind()方法:
protected void doBind(SocketAddress localAddress) throws Exception { //jdk版本的判断 if (PlatformDependent.javaVersion() >= 7) { javaChannel().bind(localAddress, config.getBacklog()); } else { javaChannel().socket().bind(localAddress, config.getBacklog()); }}
开始是一个jdk版本的判断, 我们以jdk7以上为例, 看到这条语句:
javaChannel().bind(localAddress, config.getBacklog());
终于找到了和jdk底层相关的绑定逻辑了, javaChannel()返回的是当前channel绑定的jdk底层的channel, 而bind()方法, 就是jdk底层的channel绑定端口的逻辑
回到bind(final SocketAddress localAddress, final ChannelPromise promise)方法:
首先看if判断:if(!wasActive && isActive())
这里意思是如果之前不是active, 绑定之后是active的话, 执行if块, 显然这里符合条件, 继续往里走
最终会走到这一步, pipeline.fireChannelActive()
这也是传输active事件, 目前我们只需知道, 事件完成之后, 会调用AbstractChannel内部类AbstractUnsafe的beginRead()方法
跟到AbstractUnsafe的beginRead()方法中:
public final void beginRead() { assertEventLoop(); if (!isActive()) { return; } try { doBeginRead(); } catch (final Exception e) { //代码省略 }}
我们关注doBeginRead()方法:
protected void doBeginRead() throws Exception { //拿到selectionKey final SelectionKey selectionKey = this.selectionKey; if (!selectionKey.isValid()) { return; } readPending = true; //获得感兴趣的事件 final int interestOps = selectionKey.interestOps(); //判断是不是对任何事件都不监听 if ((interestOps & readInterestOp) == 0) { //此条件成立 //将之前的accept事件注册, readInterest代表可以读取一个新连接的意思 selectionKey.interestOps(interestOps readInterestOp); }}
这里到了jdk底层的调用逻辑, 通过注释不难看出其中的逻辑, 我们拿到和channel绑定的jdk底层的selectionKey, 获取其监听事件, 一上节我们知道, channel注册的时候没有注册任何事件, 所以我们这里if ((interestOps & readInterestOp) == 0)返回true, 之后, 将accept事件注册到channel中, 也就是selectionKey.interestOps(interestOps readInterestOp)这步执行的
注册完accept事件之后, 就可以轮询selector, 监听是否有新连接接入了
章节总结
通过了这一章的学习, 我们了解了server启动的大概流程, 这里重点掌握整个启动脉络, 知道关键步骤在哪个类执行, 后面的章节会分析每一个模块的含义
以上就是Netty启动步骤绑定端口源码分析的详细内容,更多关于Netty启动的资料请关注盛行IT其它相关文章!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。