Construction of connection: NioSocketChannel is when activated

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.

  1. 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

  2. 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.

Figure 1: receive a client process

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:

  1. Receiving by the client NioSocketChannel doReadMessages. Of course doReadMessages where each can only read a NioSocketChannel object.
  2. 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.

  1. NioSocketChannel registration is childGroup thread.

  2. 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!

Guess you like

Origin www.cnblogs.com/binarylei/p/12640510.html