一、Netty4服务端启动代码
private static final EventLoopGroup bossGroup = new NioEventLoopGroup();
private static final EventLoopGroup workerGroup = new NioEventLoopGroup();
protected static void run() throws Exception {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup);
b.channel(NioServerSocketChannel.class);
b.childHandler(new ChannelInitializer() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast("frameDecoder", new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 4, 0, 4));
pipeline.addLast("frameEncoder", new LengthFieldPrepender(4));
pipeline.addLast("decoder", new StringDecoder(CharsetUtil.UTF_8));
pipeline.addLast("encoder", new StringEncoder(CharsetUtil.UTF_8));
pipeline.addLast(new TcpServerHandler());
}
});
b.bind("127.0.0.1", 9999).sync();
}
二、具体解析
1.初始化线程池new NioEventLoopGroup(),设置线程数,选择器提供者,线程池选择策略,任务队列拒绝策略
public NioEventLoopGroup(int nThreads, ThreadFactory threadFactory,
final SelectorProvider selectorProvider, final SelectStrategyFactory selectStrategyFactory) {
super(nThreads, threadFactory, selectorProvider, selectStrategyFactory, RejectedExecutionHandlers.reject());
}
MultithreadEventLoopGroup-》MultithreadEventExecutorGroup,省略了一些优雅关闭的钩子监听器
protected MultithreadEventExecutorGroup(int nThreads, ThreadFactory threadFactory, Object... args) {
if (threadFactory == null) {
threadFactory = newDefaultThreadFactory();
}
children = new SingleThreadEventExecutor[nThreads];
if (isPowerOfTwo(children.length)) {
chooser = new PowerOfTwoEventExecutorChooser();
} else {
chooser = new GenericEventExecutorChooser();
}
for (int i = 0; i < nThreads; i ++) {
boolean success = false;
try {
children[i] = newChild(threadFactory, args);
success = true;
}
}
}
初始化线程选择器,这里会根据是否是2的幂次来进行位运算的优化,创建线程newChild,子类NioEventLoopGroup中
protected EventExecutor newChild(ThreadFactory threadFactory, Object... args) throws Exception {
return new NioEventLoop(this, threadFactory, (SelectorProvider) args[0],
((SelectStrategyFactory) args[1]).newSelectStrategy(), (RejectedExecutionHandler) args[2]);
}
保存选择提供者并且生成Selector,用参数DISABLE_KEYSET_OPTIMIZATION决定是否开启selectedKeys优化
NioEventLoop(NioEventLoopGroup parent, ThreadFactory threadFactory, SelectorProvider selectorProvider,
SelectStrategy strategy, RejectedExecutionHandler rejectedExecutionHandler) {
super(parent, threadFactory, false, DEFAULT_MAX_PENDING_TASKS, rejectedExecutionHandler);
provider = selectorProvider;
selector = openSelector();
selectStrategy = strategy;
}
SingleThreadEventLoop-》SingleThreadEventExecutor,省略了优雅关闭等收尾代码,设置最大待处理任务队列LinkedBlockingQueue,一个线程thread 就创建完成。放入EventExecutor[] children保存起来。
protected SingleThreadEventExecutor(
EventExecutorGroup parent, ThreadFactory threadFactory, boolean addTaskWakesUp, int maxPendingTasks,
RejectedExecutionHandler rejectedHandler) {
this.parent = parent;
this.addTaskWakesUp = addTaskWakesUp;
thread = threadFactory.newThread(new Runnable() {
@Override
public void run() {
boolean success = false;
updateLastExecutionTime();
try {
SingleThreadEventExecutor.this.run();
success = true;
}
}
});
threadProperties = new DefaultThreadProperties(thread);
this.maxPendingTasks = Math.max(16, maxPendingTasks);
taskQueue = newTaskQueue();
rejectedExecutionHandler = ObjectUtil.checkNotNull(rejectedHandler, "rejectedHandler");
}
2.初始化ServerBootstrap ,b.group(bossGroup, workerGroup)设置两个线程池,bossGroup监听本地绑定端口,接收客户端连接请求,然后在workerGroup给这个客户端Channel分配一个线程进行后续处理,一般情况下客户端不是很多时这个通常可以设置成1,NioEventLoopGroup默认值是处理器核心数的两倍,第二个具体处理与客户端的I/O读写请求以及一些服务端的任务。设置AbstractBootstrap属性group为bossGroup,ServerBootstrap属性childGroup为workerGroup,b.channel(NioServerSocketChannel.class)设置服务端通讯方式(nio,oio,epoll),AbstractBootstrap属性channelFactory为new BootstrapChannelFactory
3.绑定ip端口b.bind("127.0.0.1", 9999).sync();AbstractBootstrap绑定ip端口,初始化注册通道等等处理,如果同步没执行完成,设置监听器进行异步处理
private ChannelFuture doBind(final SocketAddress localAddress) {
final ChannelFuture regFuture = initAndRegister();
final Channel channel = regFuture.channel();
if (regFuture.cause() != null) {
return regFuture;
}
if (regFuture.isDone()) {
// At this point we know that the registration was complete and successful.
ChannelPromise promise = channel.newPromise();
doBind0(regFuture, channel, localAddress, promise);
return promise;
} else {
// Registration future is almost always fulfilled already, but just in case it's not.
final PendingRegistrationPromise promise = new PendingRegistrationPromise(channel);
regFuture.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
Throwable cause = future.cause();
if (cause != null) {
// Registration on the EventLoop failed so fail the ChannelPromise directly to not cause an
// IllegalStateException once we try to access the EventLoop of the Channel.
promise.setFailure(cause);
} else {
// Registration was successful, so set the correct executor to use.
// See https://github.com/netty/netty/issues/2586
promise.executor = channel.eventLoop();
doBind0(regFuture, channel, localAddress, promise);
}
}
});
return promise;
}
}
4.创建NioServerSocketChannel实例
final ChannelFuture initAndRegister() {
Channel channel = null;
try {
channel = channelFactory().newChannel();
init(channel);
}
ChannelFuture regFuture = group().register(channel);
return regFuture;
}
private static final SelectorProvider DEFAULT_SELECTOR_PROVIDER = SelectorProvider.provider();
private static ServerSocketChannel newSocket(SelectorProvider provider) {
try {
return provider.openServerSocketChannel();
}
}
private final ServerSocketChannelConfig config;
public NioServerSocketChannel() {
this(newSocket(DEFAULT_SELECTOR_PROVIDER));
}
public NioServerSocketChannel(ServerSocketChannel channel) {
super(null, channel, SelectionKey.OP_ACCEPT);
config = new NioServerSocketChannelConfig(this, javaChannel().socket());
}
AbstractNioMessageChannel-》AbstractNioChannel,设置SelectableChannel,设置监听事件SelectionKey.OP_ACCEPT,非阻塞
protected AbstractNioChannel(Channel parent, SelectableChannel ch, int readInterestOp) {
super(parent);
this.ch = ch;
this.readInterestOp = readInterestOp;
try {
ch.configureBlocking(false);
}
}
AbstractChannel,
初始化NioMessageUnsafe用来处理网络数据交互,
protected AbstractChannel(Channel parent) {
this.parent = parent;
unsafe = newUnsafe();
pipeline = newChannelPipeline();
}
创建通道DefaultChannelPipeline,tail 和head 是管道两边的处理器,后续另外增加处理器都在这两个中间,类似链表形式
protected DefaultChannelPipeline(Channel channel) {
this.channel = ObjectUtil.checkNotNull(channel, "channel");
tail = new TailContext(this);
head = new HeadContext(this);
head.next = tail;
tail.prev = head;
}
5.
NioServerSocketChannel初始化并且设置网络属性init(channel);在ServerBootstrap中,设置Channel通道选项属性,给DefaultChannelPipeline管道增加处理器,里面是回调加异步,ServerBootstrapAcceptor处理器主要的功能是处理客户端连接请求,然后给客户端从childGroup中取出一个线程专门处理Channel请求。
void init(Channel channel) throws Exception {
final Map, Object> options = options();
synchronized (options) {
setChannelOptions(channel, options, logger);
}
final Map, Object> attrs = attrs();
synchronized (attrs) {
for (Entry, Object> e: attrs.entrySet()) {
@SuppressWarnings("unchecked")
AttributeKey
给DefaultChannelPipeline增加处理器,
public final ChannelPipeline addLast(ChannelHandler... handlers) {
return addLast(null, handlers);
}
public final ChannelPipeline addLast(EventExecutorGroup executor, ChannelHandler... handlers) {
for (ChannelHandler h: handlers) {
addLast(executor, null, h);
}
return this;
}
检查重复添加,newContext组装DefaultChannelHandlerContext,设置ChannelHandler,设置处理器输入输出属性,名字,绑定管道,线程等等
DefaultChannelHandlerContext(
DefaultChannelPipeline pipeline, EventExecutor executor, String name, ChannelHandler handler) {
super(pipeline, executor, name, isInbound(handler), isOutbound(handler));
this.handler = handler;
}
addLast0放进改管道头尾处理器的中间
private void addLast0(AbstractChannelHandlerContext newCtx) {
AbstractChannelHandlerContext prev = tail.prev;
newCtx.prev = prev;
newCtx.next = tail;
prev.next = newCtx;
tail.prev = newCtx;
}
管道没注册之前setAddPending设置AbstractChannelHandlerContext处理器上下文由INIT到ADD_PENDING,保存起来后续处理
private void callHandlerCallbackLater(AbstractChannelHandlerContext ctx, boolean added) {
assert !registered;
PendingHandlerCallback task = added ? new PendingHandlerAddedTask(ctx) : new PendingHandlerRemovedTask(ctx);
PendingHandlerCallback pending = pendingHandlerCallbackHead;
if (pending == null) {
pendingHandlerCallbackHead = task;
} else {
// Find the tail of the linked-list.
while (pending.next != null) {
pending = pending.next;
}
pending.next = task;
}
}
6.ChannelFuture regFuture = group().register(channel);把当前的NioServerSocketChannel绑定到一个线程上,MultithreadEventLoopGroup、
public ChannelFuture register(Channel channel) {
return next().register(channel);
}
MultithreadEventExecutorGroup的 chooser.next();这里通过之前设置线程选择器从之前生成的线程池中挑选出一个线程,位运算或者取模。在SingleThreadEventLoop中,创建DefaultChannelPromise保存通道和线程,是一个Future
public ChannelFuture register(Channel channel) {
return register(channel, new DefaultChannelPromise(channel, this));
}
把该线程和这个Channel 绑定在一起
public ChannelFuture register(final Channel channel, final ChannelPromise promise) {
channel.unsafe().register(this, promise);
return promise;
}
AbstractChannel的内部类AbstractUnsafe,判断线程是否为空,这个Channel 是否已经注册过isRegistered,isCompatible线程的类型是否是NioEventLoop的,设置eventLoop 属性,这里有个在netty很普遍的语句eventLoop.inEventLoop(),判断当前的线程是不是参数传过来的线程,这样可以避免并发问题,减少线程切换,如果是当前线程也就是主线程main可以直接执行程序,否则使用需要绑定的这个入参线程进行异步处理。主线程返回DefaultChannelPromise。
public final void register(EventLoop eventLoop, final ChannelPromise promise) {
AbstractChannel.this.eventLoop = eventLoop;
if (eventLoop.inEventLoop()) {
register0(promise);
} else {
try {
eventLoop.execute(new Runnable() {
@Override
public void run() {
register0(promise);
}
});
}
}
}
8.NioEventLoop线程进行处理,确保通道是打开状态,设置DefaultChannelPromise的父类DefaultPromise的属性result为UNCANCELLABLE,这里使用AtomicReferenceFieldUpdater进行更新。记录是否第一次操作,并且设置该通道已经注册,
private void register0(ChannelPromise promise) {
try {
// check if the channel is still open as it could be closed in the mean time when the register
// call was outside of the eventLoop
if (!promise.setUncancellable() || !ensureOpen(promise)) {
return;
}
boolean firstRegistration = neverRegistered;
doRegister();
neverRegistered = false;
registered = true;
// Ensure we call handlerAdded(...) before we actually notify the promise. This is needed as the
// user may already fire events through the pipeline in the ChannelFutureListener.
pipeline.invokeHandlerAddedIfNeeded();
safeSetSuccess(promise);
pipeline.fireChannelRegistered();
// Only fire a channelActive if the channel has never been registered. This prevents firing
// multiple channel actives if the channel is deregistered and re-registered.
if (isActive()) {
if (firstRegistration) {
pipeline.fireChannelActive();
} else if (config().isAutoRead()) {
// This channel was registered before and autoRead() is set. This means we need to begin read
// again so that we process inbound data.
//
// See https://github.com/netty/netty/issues/4805
beginRead();
}
}
}
}
NioServerSocketChannel通道正式开始在java网络接口注册,在他的父类AbstractNioChannel中,注册每个线程
NioEventLoop绑定的选择器Selector,监听事件为0,如果有请求到达,就会返回selectionKey ,然后获取感兴趣的事件进行下面的处理。
protected void doRegister() throws Exception {
boolean selected = false;
for (;;) {
try {
selectionKey = javaChannel().register(eventLoop().selector, 0, this);
return;
}
}
}
9.在DefaultChannelPipeline中处理前面callHandlerCallbackLater有可能放入的处理器,因为这个是NioEventLoop线程自身执行的操作,所以进行断言,第一次登记后firstRegistration设置属性为false,
final void invokeHandlerAddedIfNeeded() {
assert channel.eventLoop().inEventLoop();
if (firstRegistration) {
firstRegistration = false;
// We are now registered to the EventLoop. It's time to call the callbacks for the ChannelHandlers,
// that were added before the registration was done.
callHandlerAddedForAllHandlers();
}
}
标识注册成功,置空待处理的回调处理器pendingHandlerCallbackHead,然后执行处理器PendingHandlerAddedTask
private void callHandlerAddedForAllHandlers() {
final PendingHandlerCallback pendingHandlerCallbackHead;
synchronized (this) {
assert !registered;
// This Channel itself was registered.
registered = true;
pendingHandlerCallbackHead = this.pendingHandlerCallbackHead;
// Null out so it can be GC'ed.
this.pendingHandlerCallbackHead = null;
}
// This must happen outside of the synchronized(...) block as otherwise handlerAdded(...) may be called while
// holding the lock and so produce a deadlock if handlerAdded(...) will try to add another handler from outside
// the EventLoop.
PendingHandlerCallback task = pendingHandlerCallbackHead;
while (task != null) {
task.execute();
task = task.next;
}
}
执行execute方法,因为这块还是在同一个线程中处理,所以同步调用callHandlerAdded0(ctx);
private void callHandlerAdded0(final AbstractChannelHandlerContext ctx) {
try {
ctx.handler().handlerAdded(ctx);
ctx.setAddComplete();
}
}
这块的ctx.handler()就是前面ServerBootstrap的init方法中放入的ChannelInitializer
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
if (ctx.channel().isRegistered()) {
// This should always be true with our current DefaultChannelPipeline implementation.
// The good thing about calling initChannel(...) in handlerAdded(...) is that there will be no ordering
// suprises if a ChannelInitializer will add another ChannelInitializer. This is as all handlers
// will be added in the expected order.
initChannel(ctx);
}
}
第一次initMap是个空map,回调抽象方法的实现,
private boolean initChannel(ChannelHandlerContext ctx) throws Exception {
if (initMap.putIfAbsent(ctx, Boolean.TRUE) == null) { // Guard against re-entrance.
try {
initChannel((C) ctx.channel());
} catch (Throwable cause) {
// Explicitly call exceptionCaught(...) as we removed the handler before calling initChannel(...).
// We do so to prevent multiple calls to initChannel(...).
exceptionCaught(ctx, cause);
} finally {
remove(ctx);
}
return true;
}
return false;
}
在ServerBootstrap中,给该Channel得管道添加处理器,然后execute执行,最后移除这个上下文,因为只需要执行初始化一次。设置状态REMOVE_COMPLETE,这个预先设置的处理器就处理完毕
p.addLast(new ChannelInitializer() {
@Override
public void initChannel(Channel ch) throws Exception {
final ChannelPipeline pipeline = ch.pipeline();
ChannelHandler handler = handler();
if (handler != null) {
pipeline.addLast(handler);
}
// We add this handler via the EventLoop as the user may have used a ChannelInitializer as handler.
// In this case the initChannel(...) method will only be called after this method returns. Because
// of this we need to ensure we add our handler in a delayed fashion so all the users handler are
// placed in front of the ServerBootstrapAcceptor.
ch.eventLoop().execute(new Runnable() {
@Override
public void run() {
pipeline.addLast(new ServerBootstrapAcceptor(
currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));
}
});
}
});
10.给DefaultChannelPromise的父类DefaultPromise的属性result设置为SUCCESS,并且触发监听器
protected final void safeSetSuccess(ChannelPromise promise) {
if (!(promise instanceof VoidChannelPromise) && !promise.trySuccess()) {
logger.warn("Failed to mark a promise as success because it is done already: {}", promise);
}
}
public boolean trySuccess() {
return trySuccess(null);
}
public boolean trySuccess(V result) {
if (setSuccess0(result)) {
notifyListeners();
return true;
}
return false;
}
这里是设置SUCCESS
private boolean setSuccess0(V result) {
return setValue0(result == null ? SUCCESS : result);
}
设置成功后通知全部的等待者notifyAll
private boolean setValue0(Object objResult) {
if (RESULT_UPDATER.compareAndSet(this, null, objResult) ||
RESULT_UPDATER.compareAndSet(this, UNCANCELLABLE, objResult)) {
checkNotifyWaiters();
return true;
}
return false;
}
触发监听器,这里的监听器是在初始化线程池的时候设置的,具体在MultithreadEventExecutorGroup构造函数中e.terminationFuture().addListener(terminationListener);,l.operationComplete(future);触发完成之后返回true。
private void notifyListeners() {
EventExecutor executor = executor();
if (executor.inEventLoop()) {
final InternalThreadLocalMap threadLocals = InternalThreadLocalMap.get();
final int stackDepth = threadLocals.futureListenerStackDepth();
if (stackDepth < MAX_LISTENER_STACK_DEPTH) {
threadLocals.setFutureListenerStackDepth(stackDepth + 1);
try {
notifyListenersNow();
} finally {
threadLocals.setFutureListenerStackDepth(stackDepth);
}
return;
}
}
}
11.pipeline.fireChannelRegistered();从首处理器开始, ((ChannelInboundHandler) handler()).channelRegistered(this);
public final ChannelPipeline fireChannelRegistered() {
AbstractChannelHandlerContext.invokeChannelRegistered(head);
return this;
}
在DefaultChannelPipeline的内部类HeadContext中,因为之前设置的处理器已经触发过了,所以这个invokeHandlerAddedIfNeeded直接返回
public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
invokeHandlerAddedIfNeeded();
ctx.fireChannelRegistered();
}
依次寻找输入类型的处理器,触发他们的注册逻辑invokeChannelRegistered
public ChannelHandlerContext fireChannelRegistered() {
invokeChannelRegistered(findContextInbound());
return this;
}
判断是不是输入类型的处理器,这里返回的是TailContext,他的channelRegistered方法没有实现体,直接返回。整个过程结束
private AbstractChannelHandlerContext findContextInbound() {
AbstractChannelHandlerContext ctx = this;
do {
ctx = ctx.next;
} while (!ctx.inbound);
return ctx;
}
这个时候isActive方法javaChannel().socket().isBound();还没有激活,直接返回false,initAndRegister();方法已经结束。
12.开始绑定ip端口,通道,ChannelPromise,AbstractBootstrap,因为前面已经把regFuture也就是DefaultPromise的属性result设置为SUCCESS了。
if (regFuture.isDone()) {
// At this point we know that the registration was complete and successful.
ChannelPromise promise = channel.newPromise();
doBind0(regFuture, channel, localAddress, promise);
return promise;
}
创建一个新的DefaultChannelPromise用来保存后续所需要的异步信息,添加关闭钩子,
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() {
@Override
public void run() {
if (regFuture.isSuccess()) {
channel.bind(localAddress, promise).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
}
}
});
}
AbstractChannel
public ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise) {
return pipeline.bind(localAddress, promise);
}
DefaultChannelPipeline
public final ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise) {
return tail.bind(localAddress, promise);
}
AbstractChannelHandlerContext,进行一些必要的验证
public ChannelFuture bind(final SocketAddress localAddress, final ChannelPromise promise) {
final AbstractChannelHandlerContext next = findContextOutbound();
EventExecutor executor = next.executor();
if (executor.inEventLoop()) {
next.invokeBind(localAddress, promise);
}
return promise;
}
获取输出类型的处理器
private AbstractChannelHandlerContext findContextOutbound() {
AbstractChannelHandlerContext ctx = this;
do {
ctx = ctx.prev;
} while (!ctx.outbound);
return ctx;
}
因为这些都是在一个线程NioEventLoop里,所以可以直接同步执行,第一个处理器是HeadContext,判断设置处理器状态invokeHandler,执行绑定操作
((ChannelOutboundHandler) handler()).bind(this, localAddress, promise);
public void bind(
ChannelHandlerContext ctx, SocketAddress localAddress, ChannelPromise promise)
throws Exception {
unsafe.bind(localAddress, promise);
}
AbstractChannel的内部类AbstractUnsafe,这个unsafe实际是NioMessageUnsafe,
和注册操作类似,断言,给
DefaultPromise的
result
设置
UNCANCELLABLE
状态,获取激活状态,
public final void bind(final SocketAddress localAddress, final ChannelPromise promise) {
boolean wasActive = isActive();
try {
doBind(localAddress);
}
if (!wasActive && isActive()) {
invokeLater(new Runnable() {
@Override
public void run() {
pipeline.fireChannelActive();
}
});
}
safeSetSuccess(promise);
}
在NioServerSocketChannel中绑定doBind,设置链接队列大小Backlog,默认为200,这个参数主要是第一次握手的队列和握手成功队列的总合,一些网络攻击就是根据这个来进行实施的
protected void doBind(SocketAddress localAddress) throws Exception {
if (PlatformDependent.javaVersion() >= 7) {
javaChannel().bind(localAddress, config.getBacklog());
} else {
javaChannel().socket().bind(localAddress, config.getBacklog());
}
}
13.现在通道已经激活,稍候执行管道激活事件pipeline.fireChannelActive();设置promise成功状态、DefaultChannelPipeline
public final ChannelPipeline fireChannelActive() {
AbstractChannelHandlerContext.invokeChannelActive(head);
return this;
}
static void invokeChannelActive(final AbstractChannelHandlerContext next) {
EventExecutor executor = next.executor();
if (executor.inEventLoop()) {
next.invokeChannelActive();
}
}
HeadContext
public void channelActive(ChannelHandlerContext ctx) throws Exception {
ctx.fireChannelActive();
readIfIsAutoRead();
}
AbstractChannelHandlerContext,一次激活输入类型的处理器
public ChannelHandlerContext fireChannelActive() {
final AbstractChannelHandlerContext next = findContextInbound();
invokeChannelActive(next);
return this;
}
14.这里的处理器只有一个,也就是最开始init的ServerBootstrapAcceptor,他对此事件无任何处理,然后是TailContext也没有处理,直接返回。开始read
private void readIfIsAutoRead() {
if (channel.config().isAutoRead()) {
channel.read();
}
}
默认情况下是自动read的,AbstractChannel的 pipeline.read();-》tail.read();-》AbstractChannelHandlerContext获取HeadContext.read
public ChannelHandlerContext read() {
final AbstractChannelHandlerContext next = findContextOutbound();
EventExecutor executor = next.executor();
if (executor.inEventLoop()) {
next.invokeRead();
}
return this;
}
DefaultChannelPipeline的unsafe.beginRead();-》AbstractChannel的 doBeginRead();-》AbstractNioChannel,这个selectionKey是注册doRegister()的时候返回的,判断有效性,设置readPending正在读
protected void doBeginRead() throws Exception {
final SelectionKey selectionKey = this.selectionKey;
if (!selectionKey.isValid()) {
return;
}
readPending = true;
final int interestOps = selectionKey.interestOps();
if ((interestOps & readInterestOp) == 0) {
selectionKey.interestOps(interestOps | readInterestOp);
}
}
因为之前注册时设置interestOps为0,这次增加最开始初始化NioServerSocketChannel时的SelectionKey.OP_ACCEPT的设置,监听客户端连接事件,整个通道到此已经全部初始化注册监听完毕,
进行同步等待
sync。