Introduction
Channel is the channel for data transmission and data processing in netty, and it is also an indispensable part of the netty program. In netty, channel is an interface, and there are different implementations for different data types or protocols.
Although the channel is very important, it is really mysterious in the code, basically we rarely see the direct use of the channel, so is this really the case? What is the role of ChannelGroup related to channel? Let's take a look together.
The channel of Shenlong seeing the beginning but not the end
In fact, the code of netty has a fixed template. First, according to whether it is the server side or the client side, the corresponding Bootstrap and ServerBootstrap are created. Then configure the corresponding group method for this Bootstrap. Then configure the channel and handler for Bootstrap, and finally start Bootstrap.
Such a standard netty program is completed. All you need to do is pick the right group, channel and handler for it.
Let's first look at the simplest case of NioServerSocketChannel:
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new ChatServerInitializer());
b.bind(PORT).sync().channel().closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
Here, we set NioServerSocketChannel as ServerBootstrap's channel.
Is this the end? Where is the channel used?
Don't worry, let's take a closer look at the last sentence in the try block:
b.bind(PORT).sync().channel().closeFuture().sync();
b.bind(PORT).sync() actually returns a ChannelFuture object, and by calling its channel method, it returns the Channel object associated with it.
Then we call the channel.closeFuture() method. The closeFuture method returns a ChannelFuture object, which will be notified when the channel is closed.
The sync method will achieve synchronous blocking until the channel is closed, so as to perform the subsequent shutdown operation of the eventGroup.
In the construction of templates in ServerBootstrap, the channel actually has two functions. The first function is to specify the channel of ServerBootstrap, and the second function is to obtain the channel closing event through the channel, and finally close the entire netty program.
Although we basically can't see the direct method invocation of the channel, there is no doubt that the channel is the soul of netty.
Next, let's take a look at the basic operations of the handler for specific message processing:
public void channelActive(ChannelHandlerContext ctx) throws Exception {
// channel活跃
ctx.write("Channel Active状态!\r\n");
ctx.flush();
}
Usually, if we need to write data to the channel in the handler, we call the write method of ChannelHandlerContext. What does this method have to do with channels?
First of all, the write method is a method in the ChannelOutboundInvoker interface, and both ChannelHandlerContext and Channel inherit the ChannelOutboundInvoker interface, that is, both ChannelHandlerContext and Channel have write methods:
ChannelFuture write(Object msg);
Because we are using NioServerSocketChannel here, let's take a look at the implementation of write in NioServerSocketChannel.
After checking the code, we will find that NioServerSocketChannel inherits from AbstractNioMessageChannel, AbstractNioMessageChannel inherits from AbstractNioChannel, AbstractNioChannel inherits from AbstractChannel, and this write method is implemented in AbstractChannel:
public ChannelFuture write(Object msg) {
return pipeline.write(msg);
}
Channel's write method actually calls the pipeline's write method. The following is the write method in pipeLine:
public final ChannelFuture write(Object msg) {
return tail.write(msg);
}
The tail here is an AbstractChannelHandlerContext object.
In this way, we have come to the conclusion that the write method in the channel actually calls the write method in the ChannelHandlerContext.
So the above:
ctx.write("Channel Active状态!\r\n");
It is actually possible to call directly from the channel:
Channel ch = b.bind(0).sync().channel();
// 将消息写入channel中
ch.writeAndFlush("Channel Active状态!\r\n").sync();
channel and channelGroup
Channel is the soul of netty. For Bootstrap, to get the corresponding channel, you can call:
b.bind(PORT).sync().channel()
To get, from the above code we can also see that a Bootstrap will only correspond to one channel.
There is a parent() method in the channel, which is used to return its parent channel, so the channel has a hierarchical structure.
Let's look at the definition of channelGroup again:
public interface ChannelGroup extends Set<Channel>, Comparable<ChannelGroup>
You can see that ChannelGroup is actually a collection of Channels. ChannelGroup is used to build similar Channels into sets, so that multiple channels can be managed uniformly.
Maybe some friends want to ask, doesn't a Bootstrap only correspond to one channel? So where did the collection of channels come from?
In fact, in some complex programs, we may start multiple Bootstraps to handle different services, so there will be multiple channels accordingly.
If too many channels are created and these channels are very homogeneous, there is a need to manage these channels in a unified manner. At this time, you need to use channelGroup.
Basic use of channelGroup
Let's first look at the basic use of channelGroup, the first is to create a channelGroup:
ChannelGroup recipients =
new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
After you have a channelGroup, you can call the add method to add different channels to it:
recipients.add(channelA);
recipients.add(channelB);
And you can also send messages to these channels uniformly:
recipients.write(Unpooled.copiedBuffer(
"这是从channelGroup中发出的统一消息.",
CharsetUtil.UTF_8));
Basically channelGroup provides write, flush, flushAndWrite, writeAndFlush, disconnect, close, newCloseFuture and other functions for unified management of channels in the collection.
If you have multiple channels, consider using channelGroup.
In addition, channelGroup has some features, let's take a closer look.
Automatically remove closed channels
ChannelGroup is a collection of channels. Of course, we only want to save the channel in the open state. If it is a channel in the close state, it is too troublesome to manually remove it from the ChannelGroup.
So in ChannelGroup, if a channel is closed, it will be automatically removed from ChannelGroup. How is this function implemented?
Let's first look at the add method of channelGroup:
public boolean add(Channel channel) {
ConcurrentMap<ChannelId, Channel> map =
channel instanceof ServerChannel? serverChannels : nonServerChannels;
boolean added = map.putIfAbsent(channel.id(), channel) == null;
if (added) {
channel.closeFuture().addListener(remover);
}
if (stayClosed && closed) {
channel.close();
}
return added;
}
It can be seen that in the add method, the channel is distinguished from a server channel or a non-server channel. Then store it in ConcurrentMap according to the channel id.
If the addition is successful, a closeFuture callback is added to the channel. When the channel is closed, the remove method is called:
private final ChannelFutureListener remover = new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
remove(future.channel());
}
};
The remover method will remove the channel from serverChannels or nonServerChannels. This ensures that only channels in the open state are saved in the ChannelGroup.
Close both serverChannel and acceptedChannel
Although the bind method of ServerBootstrap will only return one channel, for the server, there can be multiple worker EventLoopGroups, so the accepted channel established after the connection between the client and the server is established is a sub-channel of the server channel.
That is to say, a server has one server channel and multiple accepted channels.
Then if we want to close these channels at the same time, we can use the close method of ChannelGroup.
Because if the server channel and the non-server channel are in the same ChannelGroup, all IO commands will be sent to the server channel first, and then to the non-server channel.
Therefore, we can add both Server channel and non-Server channel to the same ChannelGroup, and at the end of the program, call the close method of ChannelGroup uniformly to achieve this purpose:
ChannelGroup allChannels =
new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
public static void main(String[] args) throws Exception {
ServerBootstrap b = new ServerBootstrap(..);
...
b.childHandler(new MyHandler());
// 启动服务器
b.getPipeline().addLast("handler", new MyHandler());
Channel serverChannel = b.bind(..).sync();
allChannels.add(serverChannel);
... 等待shutdown指令 ...
// 关闭serverChannel 和所有的 accepted connections.
allChannels.close().awaitUninterruptibly();
}
public class MyHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelActive(ChannelHandlerContext ctx) {
// 将accepted channel添加到allChannels中
allChannels.add(ctx.channel());
super.channelActive(ctx);
}
}
ChannelGroupFuture
In addition, like channel, the operation of channelGroup is asynchronous, it will return a ChannelGroupFuture object.
Let's look at the definition of ChannelGroupFuture:
public interface ChannelGroupFuture extends Future<Void>, Iterable<ChannelFuture>
It can be seen that ChannelGroupFuture is a Future, and it is also a traverser of ChannelFuture, which can traverse the ChannelFuture returned by all channels in the ChannelGroup.
At the same time, ChannelGroupFuture provides isSuccess, isPartialSuccess, isPartialFailure and other methods to determine whether the command is partially successful.
ChannelGroupFuture also provides the addListener method to listen to specific events.
Summarize
Channel is the core of netty. When we have multiple channels that are inconvenient to manage, we can use channelGroup for unified management.
This article has been included in http://www.flydean.com/04-1-netty-channel-group/
The most popular interpretation, the most profound dry goods, the most concise tutorials, and many tricks you don't know are waiting for you to discover!
Welcome to pay attention to my official account: "Program those things", understand technology, understand you better!
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。