netty abstract nio message channel

netty channel interface definition: http://donald-draper.iteye.com/blog/2392740
netty abstract channel initialization: http://donald-draper.iteye.com/blog/2392801
netty abstract Unsafe definition: http://donald -draper.iteye.com/blog/2393053
netty channel outbound buffer: http://donald-draper.iteye.com/blog/2393098
netty abstract channel follow-up: http://donald-draper.iteye.com/blog/ 2393166
netty abstracts nio channels: http://donald-draper.iteye.com/blog/2393269
netty abstracts nio byte channels: http://donald-draper.iteye.com/blog/2393323
Introduction The
last article we read To abstract the nio byte channel, let's review:
Write the channel outbound buffer, that is, traverse the write request on the refresh chain. If the write request message is a byte buf, call doWriteBytes to complete the actual data sending operation. After the subclass is extended, if the write request message is a file region, call doWriteFileRegion to complete the actual data transmission operation. For the data sending operation, when the subclass is extended and the data is sent, the data sending progress of the channel will be updated, and the write request will be removed from the refresh chain; if all write requests have been sent, the write operation event will be re-added to the selected key interest event set. Otherwise, continue to flush the write request in the channel's outbound buffer.

nio byte Unsafe read operation, read data from the channel receiving buffer, notify the channel to process the read data, trigger the fireChannelRead event of the Channel pipeline, and trigger the fireChannelReadComplete event of the Channel pipeline when the data is read. If the channel is closed, the channel input close event (fireUserEventTriggered) will be triggered. If an exception occurs during the process of reading data, the unread data in the buffer will be read, and the channel will process the remaining data.
The abstract nio byte channel is a byte-oriented channel and is the parent class of the Socket channel.
Today we will look at the parent class of the ServerSocket channel, AbstractNioMessageChannel, a message-oriented channel:
package io.netty.channel.nio;

import io.netty.channel.Channel;
import io.netty.channel.ChannelConfig;
import io.netty.channel.ChannelOutboundBuffer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.RecvByteBufAllocator;
import io.netty.channel.ServerChannel;

import java.io.IOException;
import java.net.PortUnreachableException;
import java.nio.channels.SelectableChannel;
import java.nio.channels.SelectionKey;
import java.util.ArrayList;
import java.util.List;

/**
 * {@link AbstractNioChannel} base class for {@link Channel}s that operate on messages.
 */
public abstract class AbstractNioMessageChannel extends AbstractNioChannel {
    boolean inputShutdown;//Whether to close the input stream

    /**
     * @see AbstractNioChannel#AbstractNioChannel(Channel, SelectableChannel, int)
     */
    protected AbstractNioMessageChannel(Channel parent, SelectableChannel ch, int readInterestOp) {
        super(parent, ch, readInterestOp);
    }
}

Let's see the actual write operation:
@Override
protected void doWrite(ChannelOutboundBuffer in) throws Exception {
    final SelectionKey key = selectionKey();
    final int interestOps = key.interestOps();

    for (;;) {
        Object msg = in.current();
        if (msg == null) {
            // Wrote all messages.
            if ((interestOps & SelectionKey.OP_WRITE) != 0) {
	       //The message has been sent, remove the write operation event from the selected key interest set
                key.interestOps(interestOps & ~SelectionKey.OP_WRITE);
            }
            break;
        }
        try {
            boolean done = false;
            for (int i = config().getWriteSpinCount() - 1; i >= 0; i--) {
	        //write message
                if (doWriteMessage(msg, in)) {
                    done = true;
                    break;
                }
            }

            if (done) {//If the message is read, remove the write request from the channel refresh chain
                in.remove();
            } else {
                // Did not write all messages.
                if ((interestOps & SelectionKey.OP_WRITE) == 0) {
		    //The message has not been sent, if you need to add a write event to the interest event set of the selected key
                    key.interestOps(interestOps | SelectionKey.OP_WRITE);
                }
                break;
            }
        } catch (IOException e) {
            if (continueOnWriteError()) {
	        //If the write request needs to be removed when the write exception occurs, remove it
                in.remove(e);
            } else {
                throw e;
            }
        }
    }
}

/**
 * Write a message to the underlying {@link java.nio.channels.Channel}.
 *Write a message to the underlying channel, to be extended by subclasses
 * @return {@code true} if and only if the message has been written
 */
protected abstract boolean doWriteMessage(Object msg, ChannelOutboundBuffer in) throws Exception;
/**

 * Returns {@code true} if we should continue the write loop on a write error.
 */
protected boolean continueOnWriteError() {
    return false;
}

It can be seen from the above that the Nio message channel is abstracted, and the channel outbound buffer message is written, that is, the channel outbound buffer refresh chain is traversed. When the write message request is empty, the write operation event is removed from the selected key interest set, otherwise, the doWriteMessage method is delegated , write the message to the underlying channel, the doWriteMessage method needs to be extended by the subclass, after writing, remove the write request from the refresh chain, otherwise, if necessary, add the write event to the interest event set of the selected key.

Let's look at other methods:
//start read operation
@Override
protected void doBeginRead() throws Exception {
    if (inputShutdown) {
        return;
    }
    super.doBeginRead ();
}
//Create an Unsafe to communicate with the underlying channel
@Override
protected AbstractNioUnsafe newUnsafe() {
    return new NioMessageUnsafe();
}


As can be seen from the above method, the actual return is the nio message Unsafe, let's look at NioMessageUnsafe,
private final class NioMessageUnsafe extends AbstractNioUnsafe {
    private final List<Object> readBuf = new ArrayList<Object>();
    @Override
    public void read() {
        assert eventLoop().inEventLoop();
	//Get channel configuration, Channel pipeline, accept byte buf allocator Handle
        final ChannelConfig config = config();
        final ChannelPipeline pipeline = pipeline();
        final RecvByteBufAllocator.Handle allocHandle = unsafe().recvBufAllocHandle();
        allocHandle.reset(config);
        boolean closed = false;
        Throwable exception = null;
        try {
            try {
                do {
		    //read data from channel buffer
                    int localRead = doReadMessages(readBuf);
                    if (localRead == 0) {
		       // no data to read
                        break;
                    }
                    if (localRead < 0) {
		       //The channel is closed
                        closed = true;
                        break;
                    }
                    //Update the read message counter
                    allocHandle.incMessagesRead(localRead);
                } while (allocHandle.continueReading());
            } catch (Throwable t) {
                exception = t;
            }
            
            int size = readBuf.size();
	    / / Traverse the read message set, notify the channel to process the message, that is, trigger the pipeline fireChannelRead event
            for (int i = 0; i < size; i ++) {
                readPending = false;
                pipeline.fireChannelRead(readBuf.get(i));
            }
            readBuf.clear();
            allocHandle.readComplete();
	    / / After reading, trigger the pipeline fireChannelReadComplete event
            pipeline.fireChannelReadComplete();

            if (exception != null) {
	        / / According to the exception to determine whether it is necessary, close the read task
                closed = closeOnReadError(exception);
                //Trigger the channel fireExceptionCaught event
                pipeline.fireExceptionCaught(exception);
            }

            if (closed) {
	        //Close the read task
                inputShutdown = true;
                if (isOpen()) {
                    close(voidPromise());
                }
            }
        } finally {
            // Check if there is a readPending which was not processed yet.
            // This could be for two reasons:
            // * The user called Channel.read() or ChannelHandlerContext.read() in channelRead(...) method
            // * The user called Channel.read() or ChannelHandlerContext.read() in channelReadComplete(...) method
            //
            // See https://github.com/netty/netty/issues/2254
            if (!readPending && !config.isAutoRead()) {
	        //If the read task is completed and automatic reading is not required, remove the read operation event from the selected key interest event set
                removeReadOp();
            }
        }
    }
}

//AbstractNioMessageChannel

/**
 * Read messages into the given array and return the amount which was read.
 Read messages from the channel buffer, in the buf set specified by the method, and return the number of messages read, to be extended by subclasses
 */
protected abstract int doReadMessages(List<Object> buf) throws Exception;


/ / Determine whether the read task needs to be closed when an exception occurs
protected boolean closeOnReadError(Throwable cause) {
    // ServerChannel should not be closed even on IOException because it can often continue
    // accepting incoming connections. (e.g. too many open files)
    return cause instanceof IOException &&
            !(cause instanceof PortUnreachableException) &&
            !(this instanceof ServerChannel);
}

It can be seen from the above: nio message Unsafe read operation, read data from the channel receiving buffer,
notify the channel to process the read data, trigger the fireChannelRead event of the Channel pipeline, and trigger the fireChannelReadComplete event of the Channel pipeline when the data is read
. If the channel is closed during the process of reading data,
the channel input close event (fireUserEventTriggered) will be triggered. If an exception occurs during the process of reading data,
the channel fireExceptionCaught event will be triggered. If the reading task is completed and automatic reading is not required,
select The key interest event set removes the read operation event



Summary
: Abstract the Nio message channel AbstractNioMessageChannel, write the channel outbound buffer message, that is, traverse the channel outbound buffer refresh chain, when the write message request is empty, remove the write operation from the selected key interest set Event, otherwise, delegate the doWriteMessage method to write the message to the underlying channel. The doWriteMessage method needs to be extended by the subclass. After writing, remove the write request from the refresh chain, otherwise, if necessary, add the write event to the interest event set of the selected key .

Nio message Unsafe (NioMessageUnsafe) read operation, read data from the channel receiving buffer, notify the channel to process the read data, trigger the fireChannelRead event of the Channel pipeline, and trigger the fireChannelReadComplete event of the Channel pipeline when the data is read. During the process, the channel is closed, and the channel input close event (fireUserEventTriggered) is triggered. If an exception occurs during the process of reading data, the channel fireExceptionCaught event is triggered. If the reading task is completed, and automatic reading is not required, select the key interest event from set remove read operation event

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326247588&siteId=291194637