introducción
Último artículo principalmente Netty
proceso de inicio, la participación de los NioEventLoopGroup
detalles relevantes se describen en detalle, este artículo se presentan una serie de otros pasos de inicialización de arranque.
Channel
proceso de creación e inicialización- resumen
En primer lugar, el Channel
proceso de creación e inicialización
Channel
Es Netty
para se implementa la capa de abstracción de red, que puede corresponder a JDK
la NIO
aplicación del paquete, Netty
el lado del servicio de Channel
tipo NioServerSocketChannel
. Para analizar la siguiente NioServerSocketChannel
creado e inicializado.
1, Port Binding
Durante la operación de inicio es un enlace importante puerto, y NioServerSocketChannel
la creación se lleva a cabo en este proceso. ServerBootStrap
el bind()
método
ChannelFuture f = b.bind(PORT).sync();
Ver el código fuente correspondiente, la llamada real es AbstractBootstrap
la clase bind
método:
...
public ChannelFuture bind(int inetPort) {
return bind(new InetSocketAddress(inetPort));
}
...
public ChannelFuture bind(SocketAddress localAddress) {
validate();
return doBind(ObjectUtil.checkNotNull(localAddress, "localAddress"));
}
...
private ChannelFuture doBind(final SocketAddress localAddress) {
//初始化channel
final ChannelFuture regFuture = initAndRegister();
final Channel channel = regFuture.channel();
if (regFuture.cause() != null) {
return regFuture;
}
//若注册成功,则进行bind操作
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.registered();
doBind0(regFuture, channel, localAddress, promise);
}
}
});
return promise;
}
}
2. CrearNioServerSocketChannel
initAndRegister()
Completado NioServerSocketChannel
la inicialización y registro de la operación, después de la inicialización y el registro es completa, la operación de unión real, seguimos mirando hacia abajo:
final ChannelFuture initAndRegister() {
Channel channel = null;
try {
//channel工厂创建新的channel
channel = channelFactory.newChannel();
//初始化channel
init(channel);
} catch (Throwable t) {
if (channel != null) {
// channel can be null if newChannel crashed (eg SocketException("too many open files"))
channel.unsafe().closeForcibly();
// as the Channel is not registered yet we need to force the usage of the GlobalEventExecutor
return new DefaultChannelPromise(channel, GlobalEventExecutor.INSTANCE).setFailure(t);
}
// as the Channel is not registered yet we need to force the usage of the GlobalEventExecutor
return new DefaultChannelPromise(new FailedChannel(), GlobalEventExecutor.INSTANCE).setFailure(t);
}
//注册channel
ChannelFuture regFuture = config().group().register(channel);
if (regFuture.cause() != null) {
if (channel.isRegistered()) {
channel.close();
} else {
channel.unsafe().closeForcibly();
}
}
// If we are here and the promise is not failed, it's one of the following cases:
// 1) If we attempted registration from the event loop, the registration has been completed at this point.
// i.e. It's safe to attempt bind() or connect() now because the channel has been registered.
// 2) If we attempted registration from the other thread, the registration request has been successfully
// added to the event loop's task queue for later execution.
// i.e. It's safe to attempt bind() or connect() now:
// because bind() or connect() will be executed *after* the scheduled registration task is executed
// because register(), bind(), and connect() are all bound to the same thread.
return regFuture;
}
La creación de channel
la llamada real es ReflectiveChannelFactory
en el newChannel
método.
public class ReflectiveChannelFactory<T extends Channel> implements ChannelFactory<T> {
private final Constructor<? extends T> constructor;
public ReflectiveChannelFactory(Class<? extends T> clazz) {
ObjectUtil.checkNotNull(clazz, "clazz");
try {
this.constructor = clazz.getConstructor();
} catch (NoSuchMethodException e) {
throw new IllegalArgumentException("Class " + StringUtil.simpleClassName(clazz) +
" does not have a public non-arg constructor", e);
}
}
@Override
public T newChannel() {
try {
return constructor.newInstance();
} catch (Throwable t) {
throw new ChannelException("Unable to create Channel from class " + constructor.getDeclaringClass(), t);
}
}
...
}
De lo anterior se puede ver el código, clazz.getConstructor().newInstance()
creado por medio de la reflexión Channel
.
Channel
Una vez creada, lleve a cabo Channel
la operación de inicialización,
@Override
void init(Channel channel) {
//设置channle选项
setChannelOptions(channel, options0().entrySet().toArray(newOptionArray(0)), logger);
//设置channel属性
setAttributes(channel, attrs0().entrySet().toArray(newAttrArray(0)));
ChannelPipeline p = channel.pipeline();
final EventLoopGroup currentChildGroup = childGroup;
final ChannelHandler currentChildHandler = childHandler;
final Entry<ChannelOption<?>, Object>[] currentChildOptions =
childOptions.entrySet().toArray(newOptionArray(0));
final Entry<AttributeKey<?>, Object>[] currentChildAttrs = childAttrs.entrySet().toArray(newAttrArray(0));
p.addLast(new ChannelInitializer<Channel>() {
@Override
public void initChannel(final Channel ch) {
final ChannelPipeline pipeline = ch.pipeline();
ChannelHandler handler = config.handler();
if (handler != null) {
pipeline.addLast(handler);
}
ch.eventLoop().execute(new Runnable() {
@Override
public void run() {
pipeline.addLast(new ServerBootstrapAcceptor(
ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));
}
});
}
});
}
En segundo lugar, el resumen
Este documento describe NioServerSocketChannel
el proceso de creación y análisis de código fuente, explica más adelante en el artículo continúe funcionando después de crear el canal, tales como la espera de una conexión, y así sucesivamente.