有没有可能在执行ServerBootstrap.bind()的时候,pipeline.fireChannelActive()执行了两次?
Is there a possibility that pipeline.fireChannelActive() is executed twice when executing ServerBootstrap.bind()?
以下代码均来自Netty4.0.31.Final。 ServerBootstrap
的频道是 NioServerSocketChannel
。
ServerBootstrap.bind(int)
的主要逻辑在AbstractBootstrap.doBind(SocketAddress)
:
private ChannelFuture doBind(final SocketAddress localAddress) {
final ChannelFuture regFuture = initAndRegister();
...
if (regFuture.isDone()) {
...
doBind0(regFuture, channel, localAddress, promise);
...
} else {
regFuture.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
...
doBind0(regFuture, channel, localAddress, promise);
}
});
}
}
initAndRegister()
中的代码最终进入AbstractUnsafe.register0(ChannelPromise promise)
:
private void register0(ChannelPromise promise) {
try {
...
boolean firstRegistration = neverRegistered;
doRegister();
...
if (firstRegistration && isActive()) {
pipeline.fireChannelActive();
}
} catch (Throwable t) {
...
}
}
可以看到,pipeline.fireChannelActive()
这里可能会被执行
让我们回到 AbstractBootstrap.doBind(SocketAddress)
,在 doBind0(regFuture, channel, localAddress, promise)
中,代码最终进入 AbstractUnsafe.bind(SocketAddress,ChannelPromise)
:
public final void bind(final SocketAddress localAddress, final ChannelPromise promise) {
...
boolean wasActive = isActive();
try {
doBind(localAddress);
} catch (Throwable t) {
...
}
if (!wasActive && isActive()) {
invokeLater(new OneTimeTask() {
@Override
public void run() {
pipeline.fireChannelActive();
}
});
}
...
}
如你所见,pipeline.fireChannelActive()
也可能在这里执行
那么,有没有可能在创建绑定一个NioServerSocketChannel
的时候,pipeline.fireChannelActive()
执行了两次?
除非 isActive
可以在您指出的流程中再次从真到假再到真。我认为它只能激活一次,所以 false -> true -> false
来自您的 post 的相关代码:
boolean firstRegistration = neverRegistered;
...
if (firstRegistration && isActive()) {
pipeline.fireChannelActive(); // isActive must be TRUE
}
...
boolean wasActive = isActive();
...
// If fireChannelActive was fired, then wasActive would be true,
// preventing it from firing again
if (!wasActive && isActive()) {
invokeLater(new OneTimeTask() {
@Override
public void run() {
pipeline.fireChannelActive();
以下代码均来自Netty4.0.31.Final。 ServerBootstrap
的频道是 NioServerSocketChannel
。
ServerBootstrap.bind(int)
的主要逻辑在AbstractBootstrap.doBind(SocketAddress)
:
private ChannelFuture doBind(final SocketAddress localAddress) {
final ChannelFuture regFuture = initAndRegister();
...
if (regFuture.isDone()) {
...
doBind0(regFuture, channel, localAddress, promise);
...
} else {
regFuture.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
...
doBind0(regFuture, channel, localAddress, promise);
}
});
}
}
initAndRegister()
中的代码最终进入AbstractUnsafe.register0(ChannelPromise promise)
:
private void register0(ChannelPromise promise) {
try {
...
boolean firstRegistration = neverRegistered;
doRegister();
...
if (firstRegistration && isActive()) {
pipeline.fireChannelActive();
}
} catch (Throwable t) {
...
}
}
可以看到,pipeline.fireChannelActive()
这里可能会被执行
让我们回到 AbstractBootstrap.doBind(SocketAddress)
,在 doBind0(regFuture, channel, localAddress, promise)
中,代码最终进入 AbstractUnsafe.bind(SocketAddress,ChannelPromise)
:
public final void bind(final SocketAddress localAddress, final ChannelPromise promise) {
...
boolean wasActive = isActive();
try {
doBind(localAddress);
} catch (Throwable t) {
...
}
if (!wasActive && isActive()) {
invokeLater(new OneTimeTask() {
@Override
public void run() {
pipeline.fireChannelActive();
}
});
}
...
}
如你所见,pipeline.fireChannelActive()
也可能在这里执行
那么,有没有可能在创建绑定一个NioServerSocketChannel
的时候,pipeline.fireChannelActive()
执行了两次?
除非 isActive
可以在您指出的流程中再次从真到假再到真。我认为它只能激活一次,所以 false -> true -> false
来自您的 post 的相关代码:
boolean firstRegistration = neverRegistered;
...
if (firstRegistration && isActive()) {
pipeline.fireChannelActive(); // isActive must be TRUE
}
...
boolean wasActive = isActive();
...
// If fireChannelActive was fired, then wasActive would be true,
// preventing it from firing again
if (!wasActive && isActive()) {
invokeLater(new OneTimeTask() {
@Override
public void run() {
pipeline.fireChannelActive();