Netty源码—1.服务端启动流程二

大纲

1.服务端启动整体流程及关键方法

2.服务端启动的核心步骤

3.创建服务端Channel的源码

4.初始化服务端Channel的源码

5.注册服务端Channel的源码

6.绑定服务端端口的源码

7.服务端启动流程源码总结

5.注册服务端Channel的源码

(1)注册服务端Channel的入口

(2)注册Selector的主要步骤

(3)注册服务端Channel总结

(1)注册服务端Channel的入口

首先AbstractBootstrap的config()方法是一个抽象方法,会由ServerBootstrap来实现。

ServerBootstrap的config()方法会返回一个封装了ServerBootstrap对象的ServerBootstrapConfig对象。所以执行代码config().group()时会调用AbstractBootstrapConfig的group()方法,也就是执行ServerBootstrap的group()方法返回用户通过group()方法设置的一个NioEventLoopGroup对象。因此config().group().register(channel)最后会调用NioEventLoopGroup的register()方法。

//AbstractBootstrap is a helper class that makes it easy to bootstrap a Channel. 
//It support method-chaining to provide an easy way to configure the AbstractBootstrap.
public abstract class AbstractBootstrap<B extends AbstractBootstrap<B, C>, C extends Channel> implements Cloneable {volatile EventLoopGroup group;...final ChannelFuture initAndRegister() {Channel channel = null;...//1.创建服务端Channelchannel = channelFactory.newChannel();//2.初始化服务端Channelinit(channel);...//3.注册服务端Channel并启动一个NioEventLoop线程,通过NioEventLoopGroup的register()方法进行注册ChannelFuture regFuture = config().group().register(channel);...return regFuture;}//Returns the AbstractBootstrapConfig object that can be used to obtain the current config of the bootstrap.public abstract AbstractBootstrapConfig<B, C> config();//Returns the configured EventLoopGroup or null if non is configured yet.public final EventLoopGroup group() {return group;}...
}//Bootstrap sub-class which allows easy bootstrap of ServerChannel
public class ServerBootstrap extends AbstractBootstrap<ServerBootstrap, ServerChannel> {private final ServerBootstrapConfig config = new ServerBootstrapConfig(this);...@Overridepublic final ServerBootstrapConfig config() {return config;}...
}public abstract class AbstractBootstrapConfig<B extends AbstractBootstrap<B, C>, C extends Channel> {protected final B bootstrap;...protected AbstractBootstrapConfig(B bootstrap) {this.bootstrap = ObjectUtil.checkNotNull(bootstrap, "bootstrap");}//Returns the configured EventLoopGroup or null if non is configured yet.public final EventLoopGroup group() {//比如返回一个NioEventLoopGroup对象return bootstrap.group();}...
}

NioEventLoopGroup继承自抽象类MultithreadEventLoopGroup,调用NioEventLoopGroup的register()方法也就是调用MultithreadEventLoopGroup的register()方法。

调用NioEventLoopGroup的register()方法时,会先通过next()方法获取一个NioEventLoop对象,然后再调用NioEventLoop的register()方法。而调用NioEventLoop的register()方法,其实就是调用抽象类SingleThreadEventLoop的register()方法。

在SingleThreadEventLoop的register()方法中,promise.channel().unsafe()会返回一个Channel.Unsafe类型的对象。而AbstractChannel实现了Channel接口,AbstractChannel的内部类AbstractUnsafe也实现了Channel接口的内部接口Unsafe。

所以promise.channel().unsafe().register(this, promise)最后会调用AbstractUnsafe的register()方法。

//MultithreadEventLoopGroup implementations which is used for NIO Selector based Channels.
public class NioEventLoopGroup extends MultithreadEventLoopGroup {......
}//Abstract base class for EventLoopGroup implementations that handles their tasks with multiple threads at the same time.
public abstract class MultithreadEventLoopGroup extends MultithreadEventExecutorGroup implements EventLoopGroup {...@Overridepublic ChannelFuture register(Channel channel) {//先通过next()方法获取一个NioEventLoop,然后通过NioEventLoop.register()方法注册服务端Channelreturn next().register(channel);}@Overridepublic EventLoop next() {return (EventLoop) super.next();}...
}//SingleThreadEventLoop implementation which register the Channel's to a Selector and so does the multi-plexing of these in the event loop.
public final class NioEventLoop extends SingleThreadEventLoop {......
}//Abstract base class for EventLoops that execute all its submitted tasks in a single thread.
public abstract class SingleThreadEventLoop extends SingleThreadEventExecutor implements EventLoop {...@Overridepublic ChannelFuture register(Channel channel) {return register(new DefaultChannelPromise(channel, this));}@Overridepublic ChannelFuture register(final ChannelPromise promise) {ObjectUtil.checkNotNull(promise, "promise");//调用AbstractUnsafe的register()方法promise.channel().unsafe().register(this, promise);return promise;}...
}

所以注册服务端Channel的关键逻辑其实就体现在AbstractUnsafe的register()方法上。该方法会先将EventLoop事件循环器绑定到服务端Channel即NioServerSocketChanel上,然后再调用AbstractUnsafe的register0()方法将服务端Channel注册到Selector上。

//A skeletal Channel implementation.
public abstract class AbstractChannel extends DefaultAttributeMap implements Channel {private volatile EventLoop eventLoop;...//Unsafe implementation which sub-classes must extend and use.protected abstract class AbstractUnsafe implements Unsafe {...@Overridepublic final void register(EventLoop eventLoop, final ChannelPromise promise) {...//绑定事件循环器,即绑定一个NioEventLoop到该Channel上AbstractChannel.this.eventLoop = eventLoop;//注册Selector,并启动一个NioEventLoopif (eventLoop.inEventLoop()) {register0(promise);} else {...//通过启动这个NioEventLoop线程来调用register0()方法将这个服务端Channel注册到Selector上eventLoop.execute(new Runnable() {@Overridepublic void run() {register0(promise);}});...}}private void register0(ChannelPromise promise) {...}...}...
}

注意:AbstractUnsafe的register()方法会将前面获取到的一个NioEventLoop事件循环器绑定到服务端Channel上,之后便可以通过channel.eventLoop()来取出这个NioEventLoop事件循环器了。因此,一个服务端Channel对应一个NioEventLoop事件循环器。此外,会通过启动一个NioEventLoop线程来调用register0()方法将服务端Channel注册到Selector上。

总结:创建服务端Channel后,就会从NioEventLoopGroup中获取一个NioEventLoop出来进行绑定,并启动这个NioEventLoop线程将这个服务端Channel注册到Selector上以及执行线程的run()逻辑监听事件等。

(2)注册Selector的主要步骤

AbstractUnsafe.register0()方法主要有4个步骤。

步骤一:调用JDK底层注册服务端Channel到Selector上

doRegister()方法是由AbstractChannel的子类AbstractNioChannel来实现的。

在AbstractNioChannel的doRegister()方法中,首先获取前面创建的JDK底层NIO的Channel,然后调用JDK底层NIO的register()方法,将this也就是NioServerSocketChannel对象当作attachment绑定到JDK的Selector上。这样绑定是为了后续从Selector拿到对应的事件后,可以把Netty领域的Channel拿出来。而且注册的ops值是0,表示此时还不关注任何事件。

步骤二:回调handlerAdded事件

步骤三:传播channelRegisterd事件

步骤四:其他逻辑

//A skeletal Channel implementation.
public abstract class AbstractChannel extends DefaultAttributeMap implements Channel {private volatile EventLoop eventLoop;...//Unsafe implementation which sub-classes must extend and use.protected abstract class AbstractUnsafe implements Unsafe {...@Overridepublic final void register(EventLoop eventLoop, final ChannelPromise promise) {...//绑定事件循环器,即绑定一个NioEventLoop到该Channel上AbstractChannel.this.eventLoop = eventLoop;//注册Selector,并启动一个NioEventLoopif (eventLoop.inEventLoop()) {register0(promise);} else {...//通过启动这个NioEventLoop线程来调用register0()方法将这个服务端Channel注册到Selector上eventLoop.execute(new Runnable() {@Overridepublic void run() {register0(promise);}});...}}private void register0(ChannelPromise promise) {...boolean firstRegistration = this.neverRegistered;//1.调用JDK底层注册服务端Channel到Selector上doRegister();this.neverRegistered = false;this.registered = true;//2.回调handlerAdded事件this.pipeline.invokeHandlerAddedIfNeeded();safeSetSuccess(promise);//3.传播channelRegisterd事件到用户代码里this.pipeline.fireChannelRegistered();//4.其他逻辑if (isActive()) {if (firstRegistration) {this.pipeline.fireChannelActive();} else if (config().isAutoRead()) {beginRead();}}...}...}//Is called after the Channel is registered with its EventLoop as part of the register process.//Sub-classes may override this methodprotected void doRegister() throws Exception {// NOOP}...
}//Abstract base class for Channel implementations which use a Selector based approach.
public abstract class AbstractNioChannel extends AbstractChannel {private final SelectableChannel ch;//这是NIO中的Channelprotected final int readInterestOp;volatile SelectionKey selectionKey;...//Create a new instance//@param parent,the parent Channel by which this instance was created. May be null.//@param ch,he underlying SelectableChannel on which it operates//@param readInterestOp,the ops to set to receive data from the SelectableChannelprotected AbstractNioChannel(Channel parent, SelectableChannel ch, int readInterestOp) {super(parent);//NioServerSocketChannel.newSocket()方法通过JDK底层创建的Channel对象会被缓存在其父类AbstractNioChannel的变量ch中//可以通过NioServerSocketChannel.javaChannel()方法获取其父类AbstractNioChannel的变量chthis.ch = ch;this.readInterestOp = readInterestOp;...//设置Channel对象为非阻塞模式ch.configureBlocking(false);...}@Overrideprotected void doRegister() throws Exception {boolean selected = false;for (;;) {...//首先获取前面创建的JDK底层NIO的Channel,然后调用JDK底层NIO的register()方法,//将this也就是NioServerSocketChannel对象当作attachment绑定到JDK的Selector上;//这样绑定是为了后续从Selector拿到对应的事件后,可以把Netty领域的Channel拿出来;//而且注册的ops值是0,表示此时还不关注任何事件;selectionKey = javaChannel().register(eventLoop().selector, 0, this);return;...}}protected SelectableChannel javaChannel() {return ch;}...
}

(3)注册服务端Channel总结

注册服务端Channel的入口是AbstractChannel的内部类AbstractUnsafe的register()方法。

首先会把一个NioEventLoop线程和当前的Channel进行绑定,然后再调用AbstractUnsafe的register0()方法进行注册。而register0()方法会把前面创建的JDK底层NIO的Channel注册到Selector上,并且把Netty领域的Channel当作一个attachment绑定到Selector上去,最后回调handlerAdded事件以及传播channelRegistered事件到用户代码里。

ServerBootstrap.bind() //用户代码入口AbstractBootstrap.initAndRegister() //初始化并注册ChannelchannelFactory.newChannel() //创建服务端ChannelServerBootstrap.init() //初始化服务端ChannelNioEventLoopGroup.register() //注册服务端ChannelNioEventLoop.register() //注册服务端ChannelAbstractChannel.AbstractUnsafe.register() //注册Channel入口this.eventLoop = eventLoop //将Channel绑定NioEventLoop线程AbstractChannel.AbstractUnsafe.register0() //实际注册AbstractNioChannel.doRegister() //调用JDK底层注册Channel到SelectorinvokeHandlerAddedIfNeeded() //回调handlerAdded事件fireChannelRegistered() //传播channelRegistered事件

补充说明一:Java类是单继承的,Java接口却是多继承的。因为前者不能区分父类相同名字方法要用哪一个,后者则由于还没实现接口,即使父类有相同名字接口也不影响。

public interface EventLoop extends OrderedEventExecutor, EventLoopGroup {...
}public abstract class SingleThreadEventLoop extends SingleThreadEventExecutor implements EventLoop {...
}

补充说明二:如果监听一个端口,就创建一个服务端Channel。如果监听多个端口,就创建多个服务端Channel。

每个Channel绑定于NioEventLoopGroup的next()方法返回的一个NioEventLoop。

6.绑定服务端端口的源码

(1)绑定服务端端口的时机

(2)AbstractUnsafe.bind()方法的主要工作

(3)调用JDK底层绑定端口

(4)传播ChannelActive事件

(5)注册ACCEPT事件到Selector

(6)绑定服务端端口总结

(1)绑定服务端端口的时机

ServerBootstrap的bind()方法,首先执行AbstractBootstrap的initAndRegister()方法完成了服务端Channel的初始化和注册后,就会调用AbstractBootstrap的doBind0()方法绑定端口。

//Bootstrap sub-class which allows easy bootstrap of ServerChannel
public class ServerBootstrap extends AbstractBootstrap<ServerBootstrap, ServerChannel> {......
}//AbstractBootstrap is a helper class that makes it easy to bootstrap a Channel. 
//It support method-chaining to provide an easy way to configure the AbstractBootstrap.
//When not used in a ServerBootstrap context, the #bind() methods are useful for connectionless transports such as datagram (UDP).
public abstract class AbstractBootstrap<B extends AbstractBootstrap<B, C>, C extends Channel> implements Cloneable {...//Create a new Channel and bind it.public ChannelFuture bind(int inetPort) {//首先根据端口号创建一个InetSocketAddress对象,然后调用重载方法bind()return bind(new InetSocketAddress(inetPort));}//Create a new Channel and bind it.public ChannelFuture bind(SocketAddress localAddress) {//验证服务启动需要的必要参数validate();if (localAddress == null) throw new NullPointerException("localAddress");return doBind(ObjectUtil.checkNotNull(localAddress, "localAddress"));}private ChannelFuture doBind(final SocketAddress localAddress) {final ChannelFuture regFuture = initAndRegister();//1.初始化和注册Channelfinal Channel channel = regFuture.channel();...doBind0(regFuture, channel, localAddress, promise);//2.绑定服务端端口...return promise;}private static void doBind0(final ChannelFuture regFuture, final Channel channel,final SocketAddress localAddress, final ChannelPromise promise) {//This method is invoked before channelRegistered() is triggered.//Give user handlers a chance to set up the pipeline in its channelRegistered() implementation.channel.eventLoop().execute(new Runnable() {@Overridepublic void run() {if (regFuture.isSuccess()) {channel.bind(localAddress, promise).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);} else {promise.setFailure(regFuture.cause());}}});}...
}

(2)AbstractUnsafe.bind()方法的主要工作

AbstractBootstrap的doBind0()方法会执行代码channel.bind(),这个channel其实就是通过channelFactory工厂反射生成的NioServerSocketChannel。

所以执行channel.bind()其实就是执行AbstractChannel的bind()方法。经过逐层调用,最后会落到调用AbstractChannel内部类AbstractUnsafe的bind()方法。

AbstractUnsafe的bind()方法主要做两件事:

一.调用JDK底层绑定端口

二.传播channelActive事件并注册ACCEPT事件

//A ServerSocketChannel implementation which uses NIO selector based implementation to accept new connections.
public class NioServerSocketChannel extends AbstractNioMessageChannel implements ServerSocketChannel {...
}//AbstractNioChannel base class for Channels that operate on messages.
public abstract class AbstractNioMessageChannel extends AbstractNioChannel {...
}//Abstract base class for Channel implementations which use a Selector based approach.
public abstract class AbstractNioChannel extends AbstractChannel {...
}//A skeletal {@link Channel} implementation.
public abstract class AbstractChannel extends DefaultAttributeMap implements Channel {...private final DefaultChannelPipeline pipeline;@Overridepublic ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise) {return pipeline.bind(localAddress, promise);}...
}//The default ChannelPipeline implementation. 
//It is usually created by a Channel implementation when the Channel is created.
public class DefaultChannelPipeline implements ChannelPipeline {final AbstractChannelHandlerContext head;final AbstractChannelHandlerContext tail;...@Overridepublic final ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise) {return tail.bind(localAddress, promise);}...
}abstract class AbstractChannelHandlerContext extends DefaultAttributeMap implements ChannelHandlerContext, ResourceLeakHint {...@Overridepublic ChannelFuture bind(final SocketAddress localAddress, final ChannelPromise promise) {if (localAddress == null) throw new NullPointerException("localAddress");if (!validatePromise(promise, false)) return promise;final AbstractChannelHandlerContext next = findContextOutbound();EventExecutor executor = next.executor();if (executor.inEventLoop()) {next.invokeBind(localAddress, promise);} else {safeExecute(executor, new Runnable() {@Overridepublic void run() {next.invokeBind(localAddress, promise);}}, promise, null);}return promise;}private void invokeBind(SocketAddress localAddress, ChannelPromise promise) {if (invokeHandler()) {try {//执行DefaultChannelPipeline.HeadContext的bind()方法((ChannelOutboundHandler) handler()).bind(this, localAddress, promise);} catch (Throwable t) {notifyOutboundHandlerException(t, promise);}} else {bind(localAddress, promise);}}...
}//The default ChannelPipeline implementation. 
//It is usually created by a Channel implementation when the Channel is created.
public class DefaultChannelPipeline implements ChannelPipeline {...final class HeadContext extends AbstractChannelHandlerContext implements ChannelOutboundHandler, ChannelInboundHandler {private final Unsafe unsafe;HeadContext(DefaultChannelPipeline pipeline) {super(pipeline, null, HEAD_NAME, false, true);unsafe = pipeline.channel().unsafe();setAddComplete();}...@Overridepublic void bind(ChannelHandlerContext ctx, SocketAddress localAddress, ChannelPromise promise) throws Exception {//执行AbstractChannel内部类AbstractUnsafe的bind()方法unsafe.bind(localAddress, promise);}...}...
}//A skeletal {@link Channel} implementation.
public abstract class AbstractChannel extends DefaultAttributeMap implements Channel {private final DefaultChannelPipeline pipeline;...//Unsafe implementation which sub-classes must extend and use.protected abstract class AbstractUnsafe implements Unsafe {...@Overridepublic final void bind(final SocketAddress localAddress, final ChannelPromise promise) {...boolean wasActive = isActive();try {//1.调用JDK底层绑定端口doBind(localAddress);} catch (Throwable t) {safeSetFailure(promise, t);closeIfClosed();return;}if (!wasActive && isActive()) {invokeLater(new Runnable() {@Overridepublic void run() {//2.传播channelActive事件并注册ACCEPT事件pipeline.fireChannelActive();}});}safeSetSuccess(promise);}...}...//Bind the Channel to the SocketAddressprotected abstract void doBind(SocketAddress localAddress) throws Exception;...
}

(3)调用JDK底层绑定端口

AbstractUnsafe的bind()方法中所调用的doBind()方法是属于AbstractChannel的抽象接口,会由NioServerSocketChannel来进行具体的实现,即调用JDK底层NIO的bind()方法来绑定端口。

//A skeletal {@link Channel} implementation.
public abstract class AbstractChannel extends DefaultAttributeMap implements Channel {...//Bind the Channel to the SocketAddressprotected abstract void doBind(SocketAddress localAddress) throws Exception;...
}//A ServerSocketChannel implementation which uses NIO selector based implementation to accept new connections.
public class NioServerSocketChannel extends AbstractNioMessageChannel implements ServerSocketChannel {...@Overrideprotected void doBind(SocketAddress localAddress) throws Exception {if (PlatformDependent.javaVersion() >= 7) {javaChannel().bind(localAddress, config.getBacklog());} else {javaChannel().socket().bind(localAddress, config.getBacklog());}}@Overrideprotected ServerSocketChannel javaChannel() {return (ServerSocketChannel) super.javaChannel();}...
}//Abstract base class for Channel implementations which use a Selector based approach.
public abstract class AbstractNioChannel extends AbstractChannel {private final SelectableChannel ch;//这是NIO中的Channel...protected SelectableChannel javaChannel() {return ch;}...
}

(4)传播ChannelActive事件

绑定完端口后,就会执行代码pipeline.fireChannelActive(),也就是调用DefaultChannelPipeline.fireChannelActive()。

最后会调用DefaultChannelPipeline.HeadContext的channelActive()方法传播channelActive事件。

//The default ChannelPipeline implementation.  
//It is usually created by a Channel implementation when the Channel is created.
public class DefaultChannelPipeline implements ChannelPipeline {final AbstractChannelHandlerContext head;final AbstractChannelHandlerContext tail;...@Overridepublic final ChannelPipeline fireChannelActive() {AbstractChannelHandlerContext.invokeChannelActive(head);return this;}...
}abstract class AbstractChannelHandlerContext extends DefaultAttributeMap implements ChannelHandlerContext, ResourceLeakHint {...static void invokeChannelActive(final AbstractChannelHandlerContext next) {EventExecutor executor = next.executor();if (executor.inEventLoop()) {next.invokeChannelActive();} else {executor.execute(new Runnable() {@Overridepublic void run() {next.invokeChannelActive();}});}}private void invokeChannelActive() {if (invokeHandler()) {try {//执行DefaultChannelPipeline.HeadContext的channelActive()方法((ChannelInboundHandler) handler()).channelActive(this);} catch (Throwable t) {notifyHandlerException(t);}} else {fireChannelActive();}}
}//The default ChannelPipeline implementation. 
//It is usually created by a Channel implementation when the Channel is created.
public class DefaultChannelPipeline implements ChannelPipeline {...final class HeadContext extends AbstractChannelHandlerContext implements ChannelOutboundHandler, ChannelInboundHandler {...@Overridepublic void channelActive(ChannelHandlerContext ctx) throws Exception {//1.传播channelActive事件ctx.fireChannelActive();//2.注册ACCEPT事件readIfIsAutoRead();}...}
}

(5)注册ACCEPT事件到Selector

传播完channelActive事件后,便会调用HeadContext.readIfIsAutoRead()方法。然后逐层调用到AbstractChannel内部类AbstractUnsafe的beginRead()方法,并最终调用到AbstractNioChannel的doBeginRead()方法来注册ACCEPT事件。

//The default ChannelPipeline implementation. 
//It is usually created by a Channel implementation when the Channel is created.
public class DefaultChannelPipeline implements ChannelPipeline {private final Channel channel;...final class HeadContext extends AbstractChannelHandlerContext implements ChannelOutboundHandler, ChannelInboundHandler {...private void readIfIsAutoRead() {//isAutoRead()方法默认会返回trueif (channel.config().isAutoRead()) {//调用AbstractChannel的read()方法channel.read();}}...}
}//A skeletal {@link Channel} implementation.
public abstract class AbstractChannel extends DefaultAttributeMap implements Channel {private final DefaultChannelPipeline pipeline;...@Overridepublic Channel read() {pipeline.read();return this;}...
}//The default ChannelPipeline implementation. 
//It is usually created by a Channel implementation when the Channel is created.
public class DefaultChannelPipeline implements ChannelPipeline {final AbstractChannelHandlerContext head;final AbstractChannelHandlerContext tail;...@Overridepublic final ChannelPipeline read() {tail.read();return this;}...
}abstract class AbstractChannelHandlerContext extends DefaultAttributeMap implements ChannelHandlerContext, ResourceLeakHint {...@Overridepublic ChannelHandlerContext read() {final AbstractChannelHandlerContext next = findContextOutbound();EventExecutor executor = next.executor();if (executor.inEventLoop()) {next.invokeRead();} else {Runnable task = next.invokeReadTask;if (task == null) {next.invokeReadTask = task = new Runnable() {@Overridepublic void run() {next.invokeRead();}};}executor.execute(task);}return this;}private void invokeRead() {if (invokeHandler()) {try {//执行DefaultChannelPipeline.HeadContext的read()方法((ChannelOutboundHandler) handler()).read(this);} catch (Throwable t) {notifyHandlerException(t);}} else {read();}}...
}//The default ChannelPipeline implementation. 
//It is usually created by a Channel implementation when the Channel is created.
public class DefaultChannelPipeline implements ChannelPipeline {...final class HeadContext extends AbstractChannelHandlerContext implements ChannelOutboundHandler, ChannelInboundHandler {private final Unsafe unsafe;HeadContext(DefaultChannelPipeline pipeline) {super(pipeline, null, HEAD_NAME, false, true);unsafe = pipeline.channel().unsafe();setAddComplete();}...@Overridepublic void read(ChannelHandlerContext ctx) {unsafe.beginRead();}...}
}//A skeletal {@link Channel} implementation.
public abstract class AbstractChannel extends DefaultAttributeMap implements Channel {private final DefaultChannelPipeline pipeline;...//Unsafe implementation which sub-classes must extend and use.protected abstract class AbstractUnsafe implements Unsafe {...@Overridepublic final void beginRead() {assertEventLoop();if (!isActive()) return;try {doBeginRead();} catch (final Exception e) {invokeLater(new Runnable() {@Overridepublic void run() {pipeline.fireExceptionCaught(e);}});close(voidPromise());}}...}//Schedule a read operation.protected abstract void doBeginRead() throws Exception;...
}//Abstract base class for Channel implementations which use a Selector based approach.
public abstract class AbstractNioChannel extends AbstractChannel {protected final int readInterestOp;volatile SelectionKey selectionKey;boolean readPending;...@Overrideprotected void doBeginRead() throws Exception {//Channel.read() or ChannelHandlerContext.read() was called//this.selectionKey就是前面注册服务端Channel时返回的对象//注册服务端Channel时,注册ops的值是0,表示还不关注任何事件final SelectionKey selectionKey = this.selectionKey;if (!selectionKey.isValid()) return;readPending = true;final int interestOps = selectionKey.interestOps();//这里的readInterestOp就是前面newChannel()时传入的SelectionKey.OP_ACCEPT//所以这样要做的工作就是,告诉JDK的Selector一切工作准备就绪,只剩下把ACCEPT事件注册到Selector上if ((interestOps & readInterestOp) == 0) {//关注ACCEPT事件selectionKey.interestOps(interestOps | readInterestOp);}}...
}

(6)绑定服务端端口总结

绑定服务端端口,最终会调用JDK底层API去进行实际绑定。绑定端口成功后,会由DefaultChannelPipeline传播channelActive事件,以及把ACCEPT事件注册到Selector上,从而可以通过Selector监听新连接的接入。

ServerBootstrap.bind() //用户代码入口AbstractBootstrap.initAndRegister() //初始化并注册ChannelchannelFactory.newChannel() //创建服务端ChannelServerBootstrap.init() //初始化服务端ChannelNioEventLoopGroup.register() //注册服务端ChannelAbstractBootstrap.doBind0() //绑定服务端端口AbstractChannel.AbstractUnsafe.bind() //绑定服务端端口入口NioServerSocketChannel.doBind() //NioServerSocketChannel实现javaChannel().bind() //JDK底层API绑定端口DefaultChannelPipeline.fireChannelActive() //传播channelActive事件HeadContext.readIfIsAutoRead() //注册ACCEPT事件到Selector上

7.服务端启动流程源码总结

initAndRegister()里的newChannel()会通过反射创建JDK底层Channel,同时会创建该Channel对应的Config对象并设置该Channel为非阻塞模式。总之,创建服务端Channel时会完成Netty几大基本组件的创建。如Channel、ChannelConfig、ChannelId、Unsafe、ChannelPipeline。

初始化服务端Channel时,会设置服务端Channel和客户端Channel的Option和Attr,并且给服务端Channel添加连接接入器ServerBootstrapAcceptor用于接收新连接。

注册服务端Channel时,会调用JDK底层的API将Channel注册到Selector,同时将Netty领域的Channel当作attachment注册到Selector上,并且回调handlerAdded事件和传播channelRegistered事件到其他用户代码中。

绑定服务端端口时,会调用JDK底层API进行端口绑定并传播channelActive事件。当channelActive事件被传播后,才真正进行有效的服务端端口绑定,也就是把ACCEPT事件注册到Selector上。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/36283.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

AI重构工程设计、施工、总承包行业:从智能优化到数字孪生的产业革命

摘要 AI正深度重构工程设计、施工与总承包行业&#xff0c;推动从传统经验驱动向数据智能驱动的转型。本文系统性解析AI当前在智能优化设计、施工过程管理、全生命周期数字孪生等场景的应用&#xff0c;展望未来AI在自动化决策、跨域协同等领域的潜力&#xff0c;并从投入产出…

Java高频面试之集合-15

hello啊&#xff0c;各位观众姥爷们&#xff01;&#xff01;&#xff01;本baby今天来报道了&#xff01;哈哈哈哈哈嗝&#x1f436; 面试官&#xff1a;解决哈希冲突有哪些方法&#xff1f; 1. 开放寻址法&#xff08;Open Addressing&#xff09; 核心思想&#xff1a;当哈…

vulhub Matrix-Breakout

1.下载靶机&#xff0c;打开靶机和kali虚拟机 2.查询kali和靶机ip 3.浏览器访问 访问81端口有登陆界面 4.扫描敏感目录 kali dirb 扫描 一一访问 robot.txt提示我们继续找找&#xff0c;可能是因为我们的字典太小了&#xff0c;我们换个扫描器换个字典试下,利用kali自带的最大…

docker-compose install nginx(解决fastgpt跨区域)

CORS前言 CORS(Cross-Origin Resource Sharing,跨源资源共享)是一种安全措施,它允许或拒绝来自不同源(协议、域名、端口任一不同即为不同源)的网页访问另一源中的资源。它的主要作用如下: 同源策略限制:Web 浏览器的同源策略限制了从一个源加载的文档或脚本如何与另一…

【Java】——方法的使用(从入门到进阶)

&#x1f381;个人主页&#xff1a;User_芊芊君子 &#x1f389;欢迎大家点赞&#x1f44d;评论&#x1f4dd;收藏⭐文章 &#x1f50d;系列专栏&#xff1a;【Java】内容概括 文章目录&#xff1a; 1.方法的概念及使用1.1 什么是方法&#xff1f;1.2 方法的意义1.3 方法的定义…

STM32HAL库,解决串口UART中断接收到的第一个字节数据丢失

1.问题描述&#xff1a; 只有上电后第一次接收到的第一字节数据会丢失&#xff0c;往后再接收也不会存在问题了。 2.先贴出来重写UART中断回调函数 我在接收到第一字节数据后开启定时器中断的&#xff0c;做一个超时处理&#xff0c;每次接收到数据会对定时器计数值清零&…

Linux中安装redis

Redis的安装包&#xff0c;从官方下载下来的是c语言的源码包&#xff0c;我们需要自己编译安装。具体操作步骤如下&#xff1a; 安装redis 上传redis资源包 安装C语言的编译环境 gcc yum install -y gcc-c 解压redis源码在当前目录 tar -zxvf redis-6.2.4.tar.gz 进入解压目录…

基于 SSE 和 WebSocket 的在线文本实时传输工具

简介 在线文本实时传输工具支持 SSE&#xff08;Server-Sent Events&#xff09; 和 WebSocket&#xff0c;可在不同设备间快速共享和同步文本&#xff0c;适用于跨设备协作、远程办公和即时通讯。 核心功能 实时同步&#xff1a;文本输入后&#xff0c;另一端用户可立即看到…

【UE5 PuerTS笔记】PuerTS安装

目录 1.下载PuerTS2.下载V83.创建C项目4.拷贝puerts/unreal下的Puerts目录到您项目的Plugins目录下5.解压V8到YouProject/Plugins/Puerts/ThirdParty6.在JsEnv.build.cs中修改UseV8Version设置为你所下载的版本。7.修改CSharpParamDefaultValueMetas.cs文件增加宏定义8.取消引擎…

Baklib企业CMS元数据与协作管理优化

智能元数据驱动协作流程升级 在现代企业内容管理中&#xff0c;智能元数据系统已成为提升协作效率的核心引擎。通过自动化标签分类与语义分析技术&#xff0c;Baklib实现了文档属性的动态结构化映射&#xff0c;使跨部门协作中的信息检索效率提升超40%。其可视化流程编辑器支持…

从零开始实现 C++ TinyWebServer Buffer类详解

文章目录 为什么需要Buffer缓冲区&#xff1f;Buffer 设计Buffer 成员变量实现 ReadFD() 函数实现 WriteFD() 函数实现 MakeSpace() 函数Buffer 代码Buffer 测试 在网络编程中&#xff0c;Buffer&#xff08;缓冲区&#xff09;是一个非常重要的概念&#xff0c;它可以帮助我们…

让AI看见世界:MCP协议与服务器的工作原理

让AI看见世界&#xff1a;MCP协议与服务器的工作原理 MCP&#xff08;Model Context Protocol&#xff09;是一种创新的通信协议&#xff0c;旨在让大型语言模型能够安全、高效地与外部资源进行交互。在AI技术快速发展的今天&#xff0c;MCP正成为连接AI与现实世界的重要桥梁。…

《线程池:Linux平台编译线程池动态库发生的死锁问题》

关于如何编译动态库可以移步《Linux&#xff1a;动态库动态链接与静态库静态链接》-CSDN博客 我们写的线程池代码是闭源的&#xff0c;未来想提供给别人使用&#xff0c;只需要提供so库和头文件即可。 系统默认库文件路径为&#xff1a; usr/lib usr/loacl/lib 系统默认头文件…

Vmware中的centos7连接上网

有很多刚刚开始配置了centos7&#xff0c;然后发现不能上网现在来解决这个问题。 测试能不能上网 先还原这个设置&#xff0c;如果没有动过的话就不用&#xff0c;连接模式是NAT模式 然后进去设置网络环境&#xff0c;记得是用超级用户设置 vi /etc/sysconfig/network-script…

Nvidia 官方CUDA课程学习笔记

之前心血来潮学习了一下Nvidia CUDA&#xff0c;外行&#xff0c;文章有理解不当的地方&#xff0c;望指正。 主要根据以下Nvidia官方课程学习&#xff1a; https://www.bilibili.com/video/BV1JJ4m1P7xW/?spm_id_from333.337.search-card.all.click&vd_sourcec256dbf86b…

Harmony 配置环境,创建,运行项目

Harmony 配置环境&#xff0c;创建&#xff0c;运行项目 1 .安装IDE 鸿蒙应用开发需要使用配套的IDE——HUAWEI DevEco Studio 获取DevEco Studio安装包&#xff0c;官方下载地址为&#xff1a;https://developer.huawei.com/consumer/cn/deveco-studio/ 解压之后双击deveco-s…

基于java的ssm+JSP+MYSQL的九宫格日志网站(含LW+PPT+源码+系统演示视频+安装说明)

系统功能 管理员功能模块&#xff1a; 个人中心 用户管理 日记信息管理 美食信息管理 景点信息管理 新闻推荐管理 日志展示管理 论坛管理 我的收藏管理 管理员管理 留言板管理 系统管理 用户功能模块&#xff1a; 个人中心 日记信息管理 美食信息管理 景点信息…

R语言软件配置(自用)

①输入R: The R Project for Statistical Computing ②点击进入Cran镜像网页&#xff0c;选择清华大学镜像&#xff0c;选择自己合适的版本下载即可(以我电脑windows为例)。 ③点击base或者install R for the first time&#xff0c;然后选择Download R-4.4.3 for windows&…

【数据结构】数据结构,算法 概念

0.本篇问题&#xff1a; 数据、数据元素、数据对象、数据项之间的基本关系&#xff1f;ADT是什么&#xff1f;数据结构的三要素&#xff1f;数据的逻辑结构有哪些&#xff1f;数据的存储结构有哪些&#xff1f;算法的五个特征&#xff1f;O(1) O(logn) O(n^n) O(n) O(n^2…

Doris单价和集群的部署

1 服务器环境准备 我们这里以3台服务器为列 1.1 硬件配置 Centos7.1及以上Ubuntu16.04及以上java1.8及以上GCC4.8.2及以上 每台服务器磁盘大小最小50G及时间相差不超或5秒 1.2 环境配置 1.2.1 修改limits.conf文件 vim /etc/security/limit.conf #在文件最后添加,*号也要添…