Mina Socket and Packet Filtering Chain

Mina filter definition: http://donald-draper.iteye.com/blog/2376161
Mina log filter and refcount filter: http://donald-draper.iteye.com/blog/2376226
Mina filter chain default build Filter : http://donald-draper.iteye.com/blog/2375985
Mina filter chain abstraction implementation: http://donald-draper.iteye.com/blog/2376335
Introduction:
We took a look at the previous article The abstract implementation of the filter chain, let's first review the
  internal association of an IoSession in AbstractIoFilterChain, use EntryImp to wrap the filter, use HashMap<String, EntryImpl> to store the filter Entry in the filter chain, the key is the filter name, and the value is the filter Entry. .
      EntryImpl is the form in which the filter exists on the filter chain. EntryImpl has a predecessor and a successor, and internally wraps a filter with name, and the filter's successor filter NextFilter. The method of passing IoHandler and IoSession events of the successor filter NextFilter is mainly to forward the event to the filter corresponding to the successor Entry. The head of the filter chain is HeadFilter, and the tail of the chain is TailFilter.
     When the HeadFilter triggers the IoHandler and IoSession events, it passes the events to the subsequent filters; but for the IoSession write/close events, in addition to passing the events, the actual event operations doWrite/doClose need to be called, and these two methods need to be implemented by subclass extensions.
     When TailFilter triggers IoHandler and IoSession events, it directly calls the related event methods of the session handler IoHandler. In the sessionOpened event, if it is a session created by SocketConnector, the related ConnectFuture should be notified; in the sessionClosed event, the filter chain should be cleared at the end; in the messageSent and messageReceived events, if the message object is a ByteBuffer, the buffer will be released.
     To add a filter to the filter chain, first check whether there is a filter on the filter chain, if not, add it;
add a filter to the head, that is, insert a filter to the back of the chain head, add a filter to the tail, that is, insert a filter To the front of the chain tail; before and after adding to the specified filter, the idea is basically the same; trigger the filter onPreAdd event before adding, and trigger the filter onPostAdd event after adding; remove the filter, first get the Entry corresponding to the filter, and then trigger the filter The onPreRemove event removes the Entry from the filter chain name2entry, then fires the filter onPostRemove event.
     The filter chain processing related event strategy is: the order of processing related events (Session*) with IoHanler is, from the head of the chain to the tail of the chain - "Iohanlder (this process handler handles related events); for session-related events (FilterWrite/close) , The processing order is Iohanlder->from the end of the chain to the head of the chain (this is a session event, just use the session to send messages in the handler method, close the session, the handler does not handle session events).
Today, let's look at the specific filter chain implementation SocketFilterChain and DatagramFilterChain. In
the article AbstractIoFilterChain, our filter chain triggers the write/close event of IoSession. In addition to passing the event,
call the actual event operation doWrite/doClose, these two methods are abstract method, which requires subclasses to extend the implementation.
In SocketFilterChain and DatagramFilterChain, it is mainly the specific implementation of the two methods doWrite/doClose.
Let's take a look at SocketFilterChain first
package org.apache.mina.transport.socket.nio;

import java.io.IOException;

import org.apache.mina.common.ByteBuffer;
import org.apache.mina.common.IoFilterChain;
import org.apache.mina.common.IoSession;
import org.apache.mina.common.IoFilter.WriteRequest;
import org.apache.mina.common.support.AbstractIoFilterChain;
import org.apache.mina.util.Queue;

/**
 * An {@link IoFilterChain} for socket transport (TCP/IP).
 *
 * @author The Apache Directory Project ([email protected])
 */
class SocketFilterChain extends AbstractIoFilterChain {

    SocketFilterChain(IoSession parent) {
        super(parent);
    }

    protected void doWrite(IoSession session, WriteRequest writeRequest) {
        SocketSessionImpl s = (SocketSessionImpl) session;
	//Get the write request queue of the Socket session, Queue inherits from AbstractList, we will talk about this later
        Queue writeRequestQueue = s.getWriteRequestQueue();

        // SocketIoProcessor.doFlush() will reset it after write is finished
        // because the buffer will be passed with messageSent event.
	//The reason for the location of the mark buffer here is that the buffer should be passed to the messageSent event.
	//After the message is sent, the SocketIoProcessor.doFlush method will reset the buffer to the current mark position
        ByteBuffer buffer = (ByteBuffer) writeRequest.getMessage();
        buffer.mark();
        int remaining = buffer.remaining();
        if (remaining == 0) {
	    //BaseIoSession
	    // private final AtomicInteger scheduledWriteRequests = new AtomicInteger();
            //Update the scheduling request counter +1
            s.increaseScheduledWriteRequests();            
        } else {
	    //BaseIoSession
	    //private final AtomicInteger scheduledWriteBytes = new AtomicInteger();
	    //Update scheduling write byte counter + buffer.remaining()
            s.increaseScheduledWriteBytes(buffer.remaining());
        }

        synchronized (writeRequestQueue) {
	   //Add the write request to the session write request queue
            writeRequestQueue.push(writeRequest);
        }
        //If the session runs a write operation, get the IoProcessor associated with the session to complete the actual message sending work, which will be described in detail later
        if (session.getTrafficMask().isWritable()) {
            s.getIoProcessor().flush(s);
        }
    }
    //Close the session
    protected void doClose(IoSession session) throws IOException {
        SocketSessionImpl s = (SocketSessionImpl) session;
        s.getIoProcessor().remove(s);//Delegated to the IoProcessor associated with the session
    }
}

Let's see the actual session closing work of SocketFilterChain
//Close the session
    protected void doClose(IoSession session) throws IOException {
        SocketSessionImpl s = (SocketSessionImpl) session;
        s.getIoProcessor().remove(s);
    }

//SocketIoProcessor
class SocketIoProcessor {
    ...
    private final Queue removingSessions = new Queue();//Store closed session queue
     void remove(SocketSessionImpl session) throws IOException {
        scheduleRemove(session);//Add the session to the queue of sessions to be removed
        startupWorker();//We will talk about this step later when we will talk about SocketIoProcessor
    }
    private void scheduleRemove(SocketSessionImpl session) {
        synchronized (removingSessions) {
            removingSessions.push(session);
        }
    }
   ...
}

Section:
SocketFilterChain sends a message first to obtain the write request queue of the Socket session; the position of the mark buffer is
mainly because the buffer is passed to the messageSent event. After the message is sent, the SocketIoProcessor.doFlush method
will reset the buffer to the current mark position; according to the buffer Determine whether to update the scheduling request counter or update the scheduling write byte counter; add the write request to the session write request queue, if the session runs a write operation, obtain the IoProcessor associated with the session to complete the actual message sending. Close the session, that is, add the session to the associated IoProcessor to be removed from the session queue.

Take another look at DatagramSessionImpl:
package org.apache.mina.transport.socket.nio.support;

import org.apache.mina.common.ByteBuffer;
import org.apache.mina.common.IoFilterChain;
import org.apache.mina.common.IoSession;
import org.apache.mina.common.IoFilter.WriteRequest;
import org.apache.mina.common.support.AbstractIoFilterChain;
import org.apache.mina.util.Queue;

/**
 * An {@link IoFilterChain} for datagram transport (UDP/IP).
 *
 * @author The Apache Directory Project ([email protected])
 */
class DatagramFilterChain extends AbstractIoFilterChain {

    DatagramFilterChain(IoSession parent) {
        super(parent);
    }

    protected void doWrite(IoSession session, WriteRequest writeRequest) {
        DatagramSessionImpl s = (DatagramSessionImpl) session;
	//Get the write request queue of the Socket session, Queue inherits from AbstractList, we will talk about this later
        Queue writeRequestQueue = s.getWriteRequestQueue();

        // SocketIoProcessor.doFlush() will reset it after write is finished
        // because the buffer will be passed with messageSent event.
        //The reason for the location of the mark buffer here is that the buffer should be passed to the messageSent event.
	//After the message is sent, the SocketIoProcessor.doFlush method will reset the buffer to the current mark position
        ByteBuffer buffer = (ByteBuffer) writeRequest.getMessage();
        buffer.mark();
        int remaining = buffer.remaining();
        if (remaining == 0) {
	    //BaseIoSession
	    // private final AtomicInteger scheduledWriteRequests = new AtomicInteger();
            //Update the scheduling request counter +1
            s.increaseScheduledWriteRequests();            
        } else {
	     //BaseIoSession
	    //private final AtomicInteger scheduledWriteBytes = new AtomicInteger();
	    //Update scheduling write byte counter + buffer.remaining()
            s.increaseScheduledWriteBytes(buffer.remaining());
            s.increaseScheduledWriteBytes(buffer.remaining());
        }

        synchronized (writeRequestQueue) {
	    //Add the write request to the session write request queue
            writeRequestQueue.push(writeRequest);
        }
        
        if (session.getTrafficMask().isWritable()) {
	     //DatagramSessionImpl
	     //private final DatagramService managerDelegate;
	    //If the session allows write operations, get the managerDelegate (DatagramService) associated with the session to complete the actual message sending work,
	    //This will be described in detail later
            s.getManagerDelegate().flushSession(s);
        }
    }

    protected void doClose(IoSession session) {
        DatagramSessionImpl s = (DatagramSessionImpl) session;
        DatagramService manager = s.getManagerDelegate();
	////Delegated to the session associated managerDelegate(DatagramService) to close the session
        if (manager instanceof DatagramConnectorDelegate) {
	    //If the DatagramConnectorDelegate directly closes the session, see it later
            ((DatagramConnectorDelegate) manager).closeSession(s);
        } else {
	    //Notify that the listener session of the DatagramAcceptorDelegate has been closed
            ((DatagramAcceptorDelegate) manager).getListeners()
                    .fireSessionDestroyed(session);
	    //Set the session CloseFuture to the closed state
            session.getCloseFuture().setClosed();
        }
    }
}

The managerDelegate (DatagramService) associated with the above DatagramSessionImpl are DatagramConnectorDelegate and DatagramAcceptorDelegate
//DatagramAcceptorDelegate
public class DatagramAcceptorDelegate extends BaseIoAcceptor implements
        IoAcceptor, DatagramService {

//DatagramConnectorDelegate
public class DatagramConnectorDelegate extends BaseIoConnector implements
        DatagramService {

Today's article is just a brief introduction, mainly to supplement the abstract implementation of the previous filter chain.
We also talked about IoService and IoProcessor involved in the article, and we will talk about it in detail later.
As can be seen from the above, when DatagramFilterChain sends a message, it first obtains the write request queue of the message session; the location of the mark buffer is mainly because the buffer needs to be passed to the messageSent event. After the message is sent, the SocketIoProcessor.doFlush method will reset the buffer to the current mark position; judge whether to update the scheduling request counter or update the scheduling write byte counter according to the actual data capacity of the buffer; add the write request to the session write request queue, if the session allows write operations, obtain the managerDelegate (DatagramService) associated with the session to complete The actual message sending works. The closing session is delegated to the managerDelegate (DatagramService) associated with the session. If the managerDelegate is the DatagramConnectorDelegate, it is directly closed. If it is the DatagramAcceptorDelegate, the listener session of the DatagramAcceptorDelegate is notified that the session has been closed, and the session CloseFuture is set to the closed state.


Summarize:
     When SocketFilterChain sends a message, it first obtains the write request queue of the Socket session; the position of the mark buffer is mainly because the buffer needs to be passed to the messageSent event. After the message is sent, the SocketIoProcessor.doFlush method will reset the buffer to the current mark position; according to the actual value of the buffer The data capacity is used to determine whether to update the scheduling request counter or update the scheduling write byte counter; add the write request to the session write request queue, if the session runs a write operation, obtain the IoProcessor associated with the session to complete the actual message sending work. Close the session, that is, add the session to the associated IoProcessor to be removed from the session queue.
      When DatagramFilterChain sends a message, it first obtains the write request queue of the message session; the position of the mark buffer is mainly because the buffer is to be passed to the messageSent event. After the message is sent, the SocketIoProcessor.doFlush method will reset the buffer to the current mark position; Determine whether to update the scheduling request counter or update the scheduling write byte counter based on the actual data capacity; add the write request to the session write request queue, and if the session allows write operations, obtain the managerDelegate (DatagramService) associated with the session to complete the actual message sending.
The closing session is delegated to the managerDelegate (DatagramService) associated with the session. If the managerDelegate is the DatagramConnectorDelegate, it is directly closed. If it is the DatagramAcceptorDelegate, the listener session of the DatagramAcceptorDelegate is notified that the session has been closed, and the session CloseFuture is set to the closed state.

Guess you like

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