1 mina体系结构

1 mina在应用程序中的地位

主要屏蔽了网络通信的一些细节,对socket进行封装,并且是NIO的一个实现框架,可以帮助我们快速的开发网络通信,常常用于用户游戏的开发,中间件等服务端程序;

2 IoServer接口

用于描述服务端和客户端的抽象;其子类IoAcceptor代表了服务端;其子类IoConnector代表了客户端;
Ioprocesser多线程环境来处理我们的连接请求流程;
IoFilter提供数据的过滤工作:包括编码、解码、日志等信息的过滤(执行在handler之前)
Handler就是我们的业务对象,自定义的Handler需要实现IoHandler(推荐继承 IoHandlerAdapter)

IoSession:就是对客户端和服务端链接的描述;常常用于发送和接受数据;主要提供对链接的管理(读取数据、发送数据、设置会话的上下文)

关系结构 、 流程顺序: IoAccepter —> IoProcesser —> IoFilter —> handler | IoSession | IoConnector —> IoProcesser —> IoFilter —> handler


2 示例1(简单示例)

mina的简单使用很常见,网上搜一下就行了;我这里有一个当时调用建设银行接口的代码 (只是客户端)

1 关键点:

  1. 自己写的handler 业务处理类
  2. 使用mina自带的行解码器(我们没有用换行符去做分割,用的是 【】)
  3. 编写客户端

    2 handler 业务处理类

    实际上重写了也是多余,啥也没干; ```java package com.yjyz.pay.core.srv.pay.platform.ccb.mina;

import org.apache.mina.core.service.IoHandlerAdapter; import org.apache.mina.core.session.IdleStatus; import org.apache.mina.core.session.IoSession;

/**

  • FileName: ClientHander
  • Autho: binC
  • Date: 2022/3/22 14:07 */ public class ClientHander extends IoHandlerAdapter {

    @Override public void sessionCreated(IoSession session) throws Exception {

    1. System.out.println(
    2. "client与:" + session.getRemoteAddress().toString() + "建立连接");

    }

    @Override public void sessionOpened(IoSession session) throws Exception {

     System.out.println("打开连接");
    

    }

    @Override public void sessionClosed(IoSession session) throws Exception {

     System.out.println(
             "client与:" + session.getRemoteAddress().toString() + "断开连接");
    

    }

    @Override public void sessionIdle(IoSession session, IdleStatus status)

         throws Exception {
     System.out.println("IDLE " + session.getIdleCount(status));
    

    }

    @Override public void exceptionCaught(IoSession session, Throwable cause)

         throws Exception {
     cause.printStackTrace();
    

    }

    @Override public void messageReceived(IoSession session, Object message)

         throws Exception {
     System.out.println("client接受信息:" + message.toString());
    

    }

    @Override public void messageSent(IoSession session, Object message)

         throws Exception {
     System.out.println("client发送信息:" + message.toString());
    

    }

}

<a name="cpg3w"></a>
####  3 客户端工具类
```java
package com.yjyz.pay.core.srv.pay.platform.ccb.mina;

import com.yjyz.core.exceptions.BusinessRtException;
import lombok.extern.slf4j.Slf4j;
import org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder;
import org.apache.mina.core.future.CloseFuture;
import org.apache.mina.core.future.ConnectFuture;
import org.apache.mina.core.future.ReadFuture;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.codec.textline.LineDelimiter;
import org.apache.mina.filter.codec.textline.TextLineCodecFactory;
import org.apache.mina.filter.logging.LoggingFilter;
import org.apache.mina.transport.socket.SocketConnector;
import org.apache.mina.transport.socket.nio.NioSocketConnector;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.stereotype.Component;

import java.io.UnsupportedEncodingException;
import java.net.InetSocketAddress;
import java.nio.charset.Charset;

/**
 * FileName: CcbClient
 * Autho: binC
 * Date:  2022/3/22 14:09
 */
// @Component
@Slf4j
public class CcbClient {

    public int PORT = 18088;//默认值
    // public static final String IP = "127.0.0.1";
    public String IP = "111.111.111.111"; //默认值
    //
    private SocketConnector connector;
    private ConnectFuture future;
    private IoSession session;
    private String lindelimit_end = "</TX>";

    public CcbClient() {
    }

    public CcbClient(String IP, int PORT) {
        this.PORT = PORT;
        this.IP = IP;
    }

    public static void main(String[] args) throws Exception {
        String ip = "111.111.111.111";
        int port = 18088;
        CcbClient client = new CcbClient(ip, port);
        String send = client.send("<?xml version=\"1.0\" encoding=\"GB2312\" standalone=\"yes\" ?><TX><REQUEST_SN>942596935052087424</REQUEST_SN><CUST_ID>客户号12312</CUST_ID><USER_ID>userid456456</USER_ID><PASSWORD>密码123456</PASSWORD><TX_CODE>6W0100</TX_CODE><LANGUAGE>CN</LANGUAGE><TX_INFO><ACC_NO>52050150383600000006</ACC_NO></TX_INFO></TX>");
        System.out.println(send);


    }

    public boolean connect() {
        /*
         * 1.创建一个socket连接,连接到服务器
         */
        connector = new NioSocketConnector();
        connector.setConnectTimeoutMillis(5000);

        /*
         * 获取过滤器链,用于添加过滤器
         */
        DefaultIoFilterChainBuilder chain = connector.getFilterChain();

        // b.添加日志过滤器
        chain.addLast("logger", new LoggingFilter());

        // c.添加字符的编码过滤器
        chain.addLast("codec", new ProtocolCodecFilter(
                new TextLineCodecFactory(
                        Charset.forName("GB18030"), 
                        LineDelimiter.DEFAULT.getValue(), 
                        lindelimit_end)));
        // chain.addLast("codec", new ProtocolCodecFilter(new PrefixedStringCodecFactory(Charset.forName("UTF-8"))));

        /*
         * 3.设置消息处理器,用于处理接收到的消息  用的是自己的handler
         */
        connector.setHandler(new ClientHander()); 

        /*
         * 4.根据IP和端口号连接到服务器
         */
        future = connector.connect(new InetSocketAddress(IP, PORT));
        // 等待连接创建完成
        future.awaitUninterruptibly();


            /*
             * 5.获取session对象,通过session可以向服务器发送消息;
             */
            session = future.getSession();
            session.getConfig().setUseReadOperation(true);

        // catch (Exception e) {
        //     e.printStackTrace();
        //     log.error("建立与建行的链接失败:"+e.getMessage());
        //     throw  e;
        // }
        return future.isConnected();
    }

    /**
     * 往服务器发送消息
     *
     * @param message
     */
    public void sendMsg2Server(String message) {
        session.write(message);
    }

    /**
     * 关闭与服务器的连接
     *
     * @return
     */
    public boolean close() {
        if (session != null) {
            session.getCloseFuture().awaitUninterruptibly(); //等待关闭连接
        }
        if (connector != null) {
            connector.dispose();
        }
        return true;
    }

    public String send(String message) throws  Exception {

        String res = null;
        try {
            connect();
            sendMsg2Server(message);
            ReadFuture readFuture = session.read().awaitUninterruptibly();
            res = (String) readFuture.getMessage() + lindelimit_end;
            // System.out.println("------------------>" + res );
        } finally {
            close();
        }
        return res;
    }
}

3 示例2 (自定义协议包的)

这个相对复杂了一些;我将代码放到了gitee上;自行去看吧,项目地址 【https://gitee.com/binC_2016/getServiceImpls/blob/master/src/main/java/com/binc/testspring/study/mina/study2/MyClient.java

study2包就是自定协议包的全部内容了,包含了服务端和客户端;
study1包是一个简单的服务端和客户端;比 (示例1)[https://www.yuque.com/binc/java/oa4r25#vVkoF] 好点 ;