Netty在注册完之后的bind方法所产生的作用
程序员文章站
2022-05-11 23:17:11
...
我们在分析完initAndRegister方法之后,随后就进入了bind端口号的操作了。
abstract void init(Channel channel) throws Exception;
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.
// 这个方法会在channelRegistered方法被触发之前调用,?给自定义的handler机会去设置pipeline在它的
// channelRegistered实现中
channel.eventLoop().execute(new Runnable() {//向当前的事件循环提交了一个任务,这个任务是在提交注册任务之后进行的,//所以一定是注册有结果了才进行的下一个任务 @Override public void run() { if (regFuture.isSuccess()) { channel.bind(localAddress, promise).addListener(ChannelFutureListener.CLOSE_ON_FAILURE); } else { promise.setFailure(regFuture.cause()); } } }); }
调用channel的bind方法
@Override
public ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise) {
return pipeline.bind(localAddress, promise);
}
再调用pipeline中的bind方法
@Override
public final ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise) {
return tail.bind(localAddress, promise);//在尾部的channelHandler的上下文对象的bind方法
}
tail中的bind方法
@Override
public ChannelFuture bind(final SocketAddress localAddress, final ChannelPromise promise) {
if (localAddress == null) {
throw new NullPointerException("localAddress");
}
if (isNotValidPromise(promise, false)) {
// cancelled
return promise;
}
final AbstractChannelHandlerContext next = findContextOutbound();
EventExecutor executor = next.executor();
if (executor.inEventLoop()) {
next.invokeBind(localAddress, promise);
} else {
safeExecute(executor, new Runnable() {
@Override
public void run() {
next.invokeBind(localAddress, promise);
}
}, promise, null);
}
return promise;
}
private void invokeBind(SocketAddress localAddress, ChannelPromise promise) {
if (invokeHandler()) {//此时的handler已经完成了add方法的调用,返回true
try {
((ChannelOutboundHandler) handler()).bind(this, localAddress, promise);
//因为一般的handler并没有对bind方法进行重写,只是继承父类的方法,直接将这个bind操作向下传递,
//随着传递的进行,到了head的handler里面,而headhandler对它进行了处理,
} catch (Throwable t) {
notifyOutboundHandlerException(t, promise);
}
} else {
bind(localAddress, promise);
}
}
下面的head中的实现
@Override
public void bind(
ChannelHandlerContext ctx, SocketAddress localAddress, ChannelPromise promise)
throws Exception {
unsafe.bind(localAddress, promise);
}
unsafe的方法中关键的代码
boolean wasActive = isActive();
try {
doBind(localAddress);
} catch (Throwable t) {
safeSetFailure(promise, t);
closeIfClosed();
return;
}
if (!wasActive && isActive()) {//因为bind端口成功,channel处于活动状态,isActive将会返回true
invokeLater(new Runnable() {//接着它又向io线程提交了一个任务,这个任务是在bind之后才执行的。
@Override
public void run() {
pipeline.fireChannelActive();//会通知在这个pipeline中的所有handler执行channelActive方法
//首当其冲的当然是我们head的handler了
}
我们看一下head中的handler回调
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
ctx.fireChannelActive();
readIfIsAutoRead();//这个关键代码,会去重新设置Channel的感兴趣key
}
private void readIfIsAutoRead() {
if (channel.config().isAutoRead()) {//默认为true
channel.read();
}
}
@Override
public final ChannelPipeline read() {
tail.read();
return this;
}
public 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() {
@Override
public void run() {
next.invokeRead();
}
};
}
executor.execute(task);
}
return this;
}
private void invokeRead() {
if (invokeHandler()) {
try {
((ChannelOutboundHandler) handler()).read(this);//一般都会将这个方法往下传递,知道handler中有真正的处理
} catch (Throwable t) {
notifyHandlerException(t);
}
} else {
read();
}
}
又回到了我们的head中
@Override
public void read(ChannelHandlerContext ctx) {
unsafe.beginRead();
}
@Override
public final void beginRead() {
assertEventLoop();
if (!isActive()) {
return;
}
try {
doBeginRead();
} catch (final Exception e) {
invokeLater(new Runnable() {
@Override
public void run() {
pipeline.fireExceptionCaught(e);
}
});
close(voidPromise());
}
}
最终来到了AbstractNioChannel @Override
protected void doBeginRead() throws Exception {
// Channel.read() or ChannelHandlerContext.read() was called
final SelectionKey selectionKey = this.selectionKey;//这个key就是我们刚开始注册0产生的key
if (!selectionKey.isValid()) {
return;
}
readPending = true;
final int interestOps = selectionKey.interestOps();
if ((interestOps & readInterestOp) == 0) {
selectionKey.interestOps(interestOps | readInterestOp);//利用我们初始化Channel时给定readInterestOp重新设置感兴趣key
上一篇: C++ bind 函数学习笔记
下一篇: js实现音量调节