Implementation of Mina Tcp Socket Client

Keywords: Session codec Apache Windows

1. Introducing dependencies

<!-- https://mvnrepository.com/artifact/org.apache.mina/mina-core -->
<dependency>
    <groupId>org.apache.mina</groupId>
    <artifactId>mina-core</artifactId>
    <version>2.0.7</version>
</dependency>

 

2. Create Connecting Clients

NioSocketConnector connector = new NioSocketConnector(); // Create Connection Client
connector.setConnectTimeoutMillis(30000); // Set connection timeout
TextLineCodecFactory factory = new TextLineCodecFactory(Charset.forName("UTF-8"));
factory.setDecoderMaxLineLength(Integer.MAX_VALUE);
connector.getFilterChain().addLast("codec", new ProtocolCodecFilter(factory));
connector.getSessionConfig().setReceiveBufferSize(Integer.MAX_VALUE); // Set Receive Buffer Size
connector.getSessionConfig().setSendBufferSize(Integer.MAX_VALUE);// Set the size of the output buffer
connector.setDefaultRemoteAddress(new InetSocketAddress(IP, Port));// Set default access address
connector.getSessionConfig().setTcpNoDelay(true);
connector.getFilterChain().addLast("threadPool", new ExecutorFilter(Executors.newCachedThreadPool()));
connector.setHandler(new DockHandler());
ConnectFuture future = connector.connect();
future.awaitUninterruptibly(); // Waiting for connection to be created successfully
IoSession session = future.getSession(); // Get Session

3. Connection failure automatic reconnection-disconnection reconnection function

Connection failure at startup Automatic reconnection:

for (;;)
{
    try
    {
        ConnectFuture future = connector.connect();
        future.awaitUninterruptibly(); // Waiting for connection to be created successfully
        IoSession session = future.getSession(); // Get Session
        log.info("Connect server[Success]");
        break;
    }
    catch (RuntimeIoException e)
    {
        log.error("Connect server[fail],5S Reconnect after");
        Thread.sleep(5000);
    }
}

Disconnected reconnection:

Disconnection reconnection function reference: https://blog.csdn.net/qq_34928194/article/details/105204583

Here's how filters work:

connector.getFilterChain().addFirst("reconnection", new IoFilterAdapter()
{
    @Override
    public void sessionClosed(NextFilter nextFilter, IoSession ioSession)
        throws Exception
    {
        for (;;)
        {
            try
            {
                Thread.sleep(3000);
                ConnectFuture future = connector.connect();
                future.awaitUninterruptibly();// Waiting for connection to be created successfully
                IoSession session = future.getSession();// Get Session
                if (session.isConnected())
                {
                    log.info("Disconnected reconnect succeeded");
                    break;
                }
            }
            catch (Exception ex)
            {
                log.info("Disconnected reconnection failed,3s Connect again");
            }
        }
    }
});

4. Heart beat settings

Use Mina's KeepAliveFilter to achieve a heartbeat: (Learn about Mina's KeepAliveFilter heartbeat mechanism)

(1) New class to implement KeepAliveMessageFactory

public class MyKeepAliveMessageFactory implements KeepAliveMessageFactory
{
    
    @Override
    public boolean isRequest(IoSession session, Object message)
    {
        return false;
    }

    @Override
    public boolean isResponse(IoSession session, Object message)
    {
        return false;
    }
    
    @Override
    public Object getRequest(IoSession session)
    {
        return "#";// Heartbeat content is #
    }
    
    @Override
    public Object getResponse(IoSession session, Object request)
    {
        return null;
    }
}

(2) Add KeepAliveFilter to session management

connector.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 10);// Set Session Properties Read-Write Channel 10 seconds without operation is considered idle
MyKeepAliveMessageFactory heartBeat = new MyKeepAliveMessageFactory();
KeepAliveFilter keepAliveFilter = new KeepAliveFilter(heartBeat, IdleStatus.READER_IDLE, KeepAliveRequestTimeoutHandler.NOOP);// Do nothing without a heartbeat response
keepAliveFilter.setForwardEvent(false);
keepAliveFilter.setRequestInterval(10);// Heart beat interval 10s
keepAliveFilter.setRequestTimeout(1);// Timeout 1s
connector.getFilterChain().addLast("heart", keepAliveFilter);

5. Method for Mina Client to Disconnect Completely

Disconnect: Mina2.0+Version: Call dispose() method of connector

How to disconnect the client completely after joining a disconnected reconnect:

After Attempt

(1) If a filter-based disconnection reconnection is used, the reconnection will occur after disconnection (even if the reconnection filter is deleted) (of course, the reconnection fails and has been reconnected). The code is as follows:

connector.getFilterChain().remove("reconnection");
connector.dispose();
// Invalid attempt

(2) If the line is disconnected and reconnected using the listener mode, the disconnection will be completely disconnected after the listener is deleted, as follows:

connector.removeListener(ioListener);// ioListener is the listener object for the disconnected reconnection created
connector.dispose();

6. Solution of sticky and half-packed problem

TextLineCodecFactory, Mina's own text-based codec, is used in this paper to transmit data based on line breaks returned (under windows is \rn, under linux is \r) and to solve the half-packet sticking problem in the decoder.

Scenario where the message is of type text string and has a line break as the data splitter (of course, you can customize the data splitter using two other constructions of TextLineCodecFactory).
For custom messages (mostly 16-bit messages), solving the half-packet sticking problem of Mina data reception requires us to customize the codec to solve this problem in the decoder.
A url:Mina custom decoder from a future blog post to solve the half-package sticky problem

 

Full Project Code Contact Acquisition

 

Posted by Wildbug on Wed, 27 May 2020 09:59:54 -0700