Serie netty: canales y grupos de canales
Aunque los canales son importantes, su código es muy misterioso y rara vez los vemos utilizados directamente. ¿Cuál es el papel de ChannelGroup en relación con los canales? Echemos un vistazo.
De hecho, el código de Netty tiene una plantilla fija. Primero, cree el Bootstrap y ServerBootstrap correspondientes según sea el servidor o el cliente, y luego configure el método de grupo correspondiente para este Bootstrap. Luego configure canales y controladores para Bootstrap y finalmente inicie Bootstrap.
De esta forma se completa un programa netty estándar. Todo lo que necesita hacer es elegir el grupo, canal y controlador adecuados.
Veamos el caso más simple de NioServerSocketChannel:
Aquí configuramos NioServerSocketChannel como el canal de ServerBootstrap.
Eso es todo, ¿para qué se utilizan exactamente los canales?
No te preocupes, echemos un vistazo más de cerca a la última oración del bloque de código de prueba:
b.bind(PORT).sync() en realidad devuelve un objeto ChannelFuture. Al llamar a su método de canal, devuelve el objeto Canal asociado a él.
Luego, llamamos al método channel.closeFuture(). closeFuture devuelve un objeto ChannelFuture que será notificado cuando se cierre el canal.
El método de sincronización implementa el bloqueo sincrónico y espera a que se cierre el canal para realizar el cierre posterior del grupo de eventos.
En la plantilla de compilación de ServerBootstrap, el canal en realidad tiene dos funciones: una es especificar el canal para ServerBootstrap y la otra es obtener el evento de cierre del canal a través del canal y finalmente cerrar todo el programa netty. .
Aunque básicamente no podemos ver llamadas directas a métodos de canales, los canales son sin duda el alma de netty.
A continuación, veamos las operaciones básicas de un controlador de mensaje específico:
Normalmente, si necesitamos escribir datos en un canal en un controlador, llamamos a la escritura del Método ChannelHandlerContext. ¿Cómo se relaciona este método con los canales?
En primer lugar, el método de escritura es un método en la interfaz ChannelOutboundInvoker. Tanto ChannelHandlerContext como Channel heredan la interfaz ChannelOutboundInvoker, es decir, tanto ChannelHandlerContext como Channel heredan la interfaz ChannelOutboundInvoker. Tanto ChannelHandlerContext como Channel tienen métodos de escritura:
Dado que aquí usamos NioServerSocketChannel, echemos un vistazo a la implementación de escritura en NioServerSocketChannel.
Después de inspeccionar el código, encontramos que NioServerSocketChannel hereda de AbstractNioMessageChannel, AbstractNioMessageChannel hereda de AbstractNioChannel y AbstractNioChannel hereda de AbstractNioChannel. AbstractNioChannel hereda de AbstractChannel y el método de escritura se implementa en AbstractChannel:
El método de escritura de Channel en realidad llama al método de escritura de pipeline. El siguiente es el método de escritura en proceso:
La cola aquí es un objeto AbstractChannelHandlerContext.
De esto podemos concluir que el método de escritura en el canal eventualmente llamará al método de escritura en ChannelHandlerContext.
Por lo tanto, lo anterior:
en realidad se puede llamar directamente desde el canal:
El canal es el alma de netty. Para Bootstrap, debes obtenerlo. el canal correspondiente se puede obtener llamando:
. Del código anterior, también podemos ver que un Bootstrap solo se usará con un canal.
Echemos un vistazo a la definición de ChannelGroup:
Puede ver que ChannelGroup es en realidad una colección de canales, que se utiliza para crear una colección similar a un canal para que pueda administrar varios canales. .
Quizás te preguntes: "¿No hay solo un canal en Bootstrap? Entonces, ¿de dónde viene el conjunto de canales?
De hecho, en algunos programas complejos, podemos iniciar varios Se utiliza un Bootstrap para manejar diferentes negocios, por lo que habrá múltiples canales en consecuencia.
Si crea demasiados canales y estos canales son muy únicos, entonces deberá administrarlos de manera unificada. Aquí es donde entran en juego los grupos de canales.
Primero, comprenda el uso básico de ChannelGroup. Primero cree un grupo de canales:
Con un grupo de canales, puede llamar al método add para agregarle otros diferentes. Canales:
Luego puedes enviar mensajes a estos canales de manera unificada:
Básicamente, un grupo de canales es un conjunto de canales que se pueden usar para enviar mensajes p>
Básicamente, channelGroup proporciona funciones de escritura, descarga, descargaAndWrite, writeAndFlush, desconexión, cierre, newCloseFuture y otras para la gestión unificada de canales en la colección.
Si tiene varios canales, considere usarlos. grupos de canales.
ChannelGroup tiene algunas características más, veámoslas en detalle.
ChannelGroup es una colección de canales. Por supuesto, solo queremos mantener los canales abiertos, pero si. El canal está cerrado y sería demasiado engorroso sacarlo manualmente del ChannelGroup
Entonces, en un ChannelGroup, si un canal está cerrado, se eliminará automáticamente del ChannelGroup
Ver primero. Método de adición de ChannelGroup:
Puede ver que el método de adición distingue entre canales de servidor y canales que no son de servidor, y luego almacena el canal en ConcurrentMap según el ID del canal
.Si la adición se realiza correctamente, se agregará el canal. Se agregará una devolución de llamada closeFuture.
Una vez cerrado el canal, se llama al método de eliminación:
El método de eliminación elimina el canal de serverChannels o nonServerChannels. El método de eliminación elimina un canal de serverChannels o nonServerChannels, asegurando que solo los canales abiertos permanezcan en el grupo de canales.
Aunque el método de vinculación de ServerBootstrap solo devolverá un canal, un servidor puede tener múltiples Worker EventLoopGroups, por lo que se llamará al método de aceptación después de que se establezca la conexión entre el cliente y el servidor.
En otras palabras, un servidor tiene un canal de servidor y múltiples canales de recepción.
Si queremos cerrar estos canales al mismo tiempo, podemos utilizar el método ChannelGroup para conseguirlo.
Por lo tanto, si queremos cerrar estos canales al mismo tiempo, podemos utilizar el método de cierre de ChannelGroup.
Porque si el canal del servidor y el canal no servidor están en el mismo ChannelGroup, todos los comandos IO se enviarán primero al canal servidor y luego al canal no servidor.
Por lo tanto, podemos lograr esto colocando el canal del servidor y el canal no servidor en el mismo ChannelGroup usando el método close y llamando al método close del ChannelGroup al final del programa:
Además, al igual que los canales, las operaciones de ChannelGroup son asíncronas.
Echemos un vistazo a la definición de ChannelGroupFuture:
Puede ver que ChannelGroupFuture es un futuro, que también es un atravesador de ChannelFuture que puede atravesar los objetos ChannelFuture devueltos por todos los canales en el grupo de canales.
Al mismo tiempo, ChannelGroupFuture proporciona isSuccess, isPartialSuccess, isPartialFailure y otros métodos para determinar si el comando tiene éxito parcial.
ChannelGroupFuture también proporciona el método addListener para escuchar eventos específicos.
Los canales son el núcleo de netty. Cuando tenemos múltiples canales que son difíciles de administrar, podemos usar channelGroup para una administración unificada.