Construction of connection: NioSocketChannel is when activated
Netty series catalog ( https://www.cnblogs.com/binarylei/p/10117436.html )
In the previous section, we analyze the boot process server, the next step is to open the door welcoming.
1. Analysis of the main line
1.1 mainline
NioEventLoop constantly poll, receiving OP_ACCEPT event; ServerBootstrapAcceptor receives a new connection initialization and registration to the childGroup. Above are at work boss thread and worker thread execution on two threads.
-
boss thread thread
-
NioEventLoop the polling selector to create a connection event (OP_ACCEPT):
-
Creating SocketChannel
-
Initialization SocketChannel and select from a worker group in NioEventLoop
-
-
worker thread thread
- The SocketChannel registered to the selector selected NioEventLoop
- Sign up reading event (OP_READ) to a selector
NioEventLoop#run
-> processSelectedKeys
-> AbstractNioMessageChannel.NioMessageUnsafe#read
-> NioServerSocketChannel#doReadMessages
-> pipeline#fireChannelRead
ServerBootstrapAcceptor#channelRead
-> EventLoopGroup#register
1.2 knowledge points
(1) the nature of connections to accept
-
selector.select () / selectNow () / select (timeoutMillis) found OP_ACCEPT event processing:
-
SocketChannel socketChannel = serverSocketChannel.accept()
-
selectionKey = javaChannel().register(eventLoop().unwrappedSelector(), 0, this);
-
selectionKey.interestOps(OP_READ);
(2)ServerBootstrapAcceptor
Create a connection initialization and registration is done through pipeline.fireChannelRead in ServerBootstrapAcceptor in.
2. Source analysis
NioServerSocketChannel will start after registration to eventLoop NioEventLoop thread, specializing in network IO event of the corresponding channel. Connection NioSocketChannel, and initializes the receiving client through OP_ACCEPT event.
Receiving a connection 2.1
(1) OP_ACCEPT event processing
processSelectedKey responsible for processing channel of OP_CONNECT, OP_WRITE, OP_READ, OP_ACCEPT event. Here we are only concerned about how OP_ACCEPT event is handled.
// 分别处理 OP_CONNECT、OP_WRITE、OP_READ、OP_ACCEPT 事件
private void processSelectedKey(SelectionKey k, AbstractNioChannel ch) {
// 省略...
final AbstractNioChannel.NioUnsafe unsafe = ch.unsafe();
int readyOps = k.readyOps();
// OP_CONNECT
if ((readyOps & SelectionKey.OP_CONNECT) != 0) {
int ops = k.interestOps();
ops &= ~SelectionKey.OP_CONNECT;
k.interestOps(ops);
unsafe.finishConnect();
}
// OP_WRITE
if ((readyOps & SelectionKey.OP_WRITE) != 0) {
ch.unsafe().forceFlush();
}
// OP_READ、OP_ACCEPT
if ((readyOps & (SelectionKey.OP_READ | SelectionKey.OP_ACCEPT)) != 0 || readyOps == 0) {
unsafe.read();
}
}
Note: you can see OP_READ and OP_ACCEPT are calling unsafe.read () process. Different Channel correspond to different unsafe, such as the corresponding NioServerSocketChannel NioMessageUnsafe, while the corresponding NioSocketChannel NioByteUnsafe. Of course, Netty relatively clever OP_READ and OP_ACCEPT unified event processing, it can also cause some confusion for us to read the source code.
(2) receiving connector
Below, we look at how NioMessageUnsafe is to receive client connections. Guess would have guessed that, certainly need to call serverSocketChannel.accept () Gets client connections.
// NioMessageUnsafe
private final List<Object> readBuf = new ArrayList<Object>();
@Override
public void read() {
// 1. 接收客户端连接请求
do {
int localRead = doReadMessages(readBuf);
if (localRead == 0) {
break;
}
if (localRead < 0) {
closed = true;
break;
}
allocHandle.incMessagesRead(localRead);
} while (allocHandle.continueReading());
// 2. 接收客户端连接请求
int size = readBuf.size();
for (int i = 0; i < size; i ++) {
pipeline.fireChannelRead(readBuf.get(i));
}
...
}
Description: NioMessageUnsafe read method done two things:
- Receiving by the client NioSocketChannel doReadMessages. Of course doReadMessages where each can only read a NioSocketChannel object.
- fireChannelRead event-triggered pipeline is completed initialization channel, if an exception is triggered fireExceptionCaught. It certainly has a Handler corresponds to deal with this NioSocketChannel.
// NioServerSocketChannel:调用 NIO 底层接收客户连接
@Override
protected int doReadMessages(List<Object> buf) throws Exception {
SocketChannel ch = SocketUtils.accept(javaChannel());
if (ch != null) {
buf.add(new NioSocketChannel(this, ch));
return 1;
}
return 0;
}
Description: the real operation of receiving the client request is delegated to the subclass NioServerSocketChannel # doReadMessages method completes. Thus, NioServerSocketChannel request has been received over NioSocketChannel, but not yet completed initialization of the channel, such as binding handler, and other parameters.
3.2 initiates the connection
Mentioned above NioServerSocketChannel during initialization will be bound ServerBootstrapAcceptor, the handler completed the initialization of the channel. The Pipeline NioServerSocketChannel follows:
We look ServerBootstrapAcceptor # channelRead direct methods. The main parameters of a TCP NioSocketChannel completed, additional properties, configuration, etc. Handler, and NioServerSocketChannel substantially identical.
public void channelRead(ChannelHandlerContext ctx, Object msg) {
final Channel child = (Channel) msg;
// 1. NioSocketChannel 绑定 handler 和相关配置参数
child.pipeline().addLast(childHandler);
// 2. 配置 Socket 的 TCP 参数和附加属性
setChannelOptions(child, childOptions, logger);
for (Entry<AttributeKey<?>, Object> e: childAttrs) {
child.attr((AttributeKey<Object>) e.getKey()).set(e.getValue());
}
// 3. NioSocketChannel 注册到 eventLoop 上
try {
childGroup.register(child).addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
if (!future.isSuccess()) {
forceClose(child, future.cause());
}
}
});
} catch (Throwable t) {
forceClose(child, t);
}
}
Description: In fact, this code and NioServerSocketChannel initialization code is similar, only caveat is NioSocketChannel slightly different registration logic.
-
NioSocketChannel registration is childGroup thread.
-
After NioSocketChannel registered to Selector success triggered pipeline.fireChannelActive () event, call its method beginRead registered OP_READ event. The NioServerSocketChannel will need to bind successfully registered OP_ACCEPT event.
childGroup.register(child)
Note: This is childGroup. How Channel is registered to NioEventLoopGroup Yes See: https://www.cnblogs.com/binarylei/p/10135712.html
The intentions of recording a little bit every day. Perhaps the content is not important, but the habit is very important!