java开发——Apache Mina的使用

Apache mina使用入门 Apache mina是一个基于NIO(非阻塞IO)模型的网络应用框架。详细资料和下载地址为:http://mina.apache.org/ 远程客户端通过IoService建立连接得到session,session将数据传送到IoFilterChain进行过滤,最后客户端在IoHandle中进行数据操作,其工作原理如图所示: 此处记录的是Android中Apache mina于服务器建立的... 阅读详情

Apache Mina是一个NIO库,实现非阻塞式通讯。它通过Java nio技术基于TCP/IP和UDP/IP协议提供了抽象的、事件驱动的、异步的API。

使用步骤:

1、配置Maven

2、配置spring

3、实现编码工厂ProtocolCodecFactory 

4、继承编码器适配器ProtocolEncoderAdapter 

5、实现解码器ProtocolDecoder 

6、继承处理器IoHandlerAdapter 

7、实现心跳工厂KeepAliveMessageFactory 

8、客户端启动

简单介绍:

1、Mina工作流程:

2、3个重要元素

3、IoSession常用方法

4、IoHandler 常用方法

1、配置Maven

<dependency>
    <groupId>org.apache.mina</groupId>
    <artifactId>mina-integration-beans</artifactId>
    <version>2.0.16</version>
</dependency>
<dependency>
    <groupId>org.apache.mina</groupId>
    <artifactId>mina-core</artifactId>
    <version>2.0.16</version>
</dependency>

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.felix</groupId>
            <artifactId>maven-bundle-plugin</artifactId>
            <extensions>true</extensions>
        </plugin>
    </plugins>
</build>

2、配置spring

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"
    default-lazy-init="false">

    <bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
        <property name="customEditors">
            <map>
                <entry key="java.net.SocketAddress"
                    value="org.apache.mina.integration.beans.InetSocketAddressEditor"></entry>
            </map>
        </property>
    </bean>

    <bean id="ioAcceptor" class="org.apache.mina.transport.socket.nio.NioSocketAcceptor"
        init-method="bind" destroy-method="unbind">
        <!--端口号 -->
        <property name="defaultLocalAddress" value=":8888"></property>
        <!--绑定自己实现的handler -->
        <property name="handler" ref="serverHandler"></property>
        <!--声明过滤器的集合 -->
        <property name="filterChainBuilder" ref="filterChainBuilder"></property>
        <property name="reuseAddress" value="true" />
    </bean>

    <bean id="filterChainBuilder"
        class="org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder">
        <property name="filters">
            <map>
                <!--mina自带的线程池filter -->
                <entry key="executor" value-ref="executorFilter"></entry>
                <entry key="mdcInjectionFilter" value-ref="mdcInjectionFilter" />
                <!--自己实现的编解码器filter -->
                <entry key="codecFilter" value-ref="codecFilter" />
                <!--日志的filter -->
                <entry key="loggingFilter" value-ref="loggingFilter" />
                <!--心跳filter -->
                <entry key="keepAliveFilter" value-ref="keepAliveFilter" />
            </map>
        </property>
    </bean>

    <!-- executorFilter多线程处理 -->
    <bean id="executorFilter" class="org.apache.mina.filter.executor.ExecutorFilter" />
    <bean id="mdcInjectionFilter" class="org.apache.mina.filter.logging.MdcInjectionFilter">
        <constructor-arg value="remoteAddress" />
    </bean>

    <!--日志 -->
    <bean id="loggingFilter" class="org.apache.mina.filter.logging.LoggingFilter" />

    <!--编解码 -->
    <bean id="codecFilter" class="org.apache.mina.filter.codec.ProtocolCodecFilter">
        <constructor-arg>
            <!--构造函数的参数传入自己实现的对象 -->
            <bean class="com.onion.mina.server.NSMinaCodeFactory"></bean>
        </constructor-arg>
    </bean>

    <!--心跳检测filter -->
    <bean id="keepAliveFilter" class="org.apache.mina.filter.keepalive.KeepAliveFilter">
        <!--构造函数的第一个参数传入自己实现的工厂 -->
        <constructor-arg>
            <bean class="com.onion.mina.server.NSMinaKeepAliveMessageFactory"></bean>
        </constructor-arg>
        <!--第二个参数需要的是IdleStatus对象,value值设置为读写空闲 -->
        <constructor-arg type="org.apache.mina.core.session.IdleStatus"
            value="BOTH_IDLE">
        </constructor-arg>
        <!--心跳频率,不设置则默认5 -->
        <property name="requestInterval" value="1500" />
        <!--心跳超时时间,不设置则默认30s -->
        <property name="requestTimeout" value="30" />
        <!--默认false,比如在心跳频率为5s时,实际上每5s会触发一次KeepAliveFilter中的session_idle事件,
        该事件中开始发送心跳包。当此参数设置为false时,对于session_idle事件不再传递给其他filter,如果设置为true,
        则会传递给其他filter,例如handler中的session_idle事件,此时也会被触发-->
        <property name="forwardEvent" value="true" />
    </bean>

    <!--自己实现的handler-->
    <bean id="serverHandler" class="com.onion.mina.server.NSMinaHandler" />
</beans>

3、实现编码工厂ProtocolCodecFactory 

public class NSMinaCodeFactory implements ProtocolCodecFactory {
    private final NSProtocalEncoder encoder;
    private final NSProtocalDecoder decoder;

    public NSMinaCodeFactory() {
        this(Charset.forName("utf-8"));
    }

    public NSMinaCodeFactory(Charset charset) {
        encoder = new NSProtocalEncoder();
        decoder = new NSProtocalDecoder();
    }

    public ProtocolDecoder getDecoder(IoSession arg0) throws Exception {
        // TODO Auto-generated method stub
        return decoder;
    }

    public ProtocolEncoder getEncoder(IoSession arg0) throws Exception {
        // TODO Auto-generated method stub
        return encoder;
    }
}

4、继承编码器适配器ProtocolEncoderAdapter 

public class NSProtocalEncoder extends ProtocolEncoderAdapter {
    private static final Logger logger = Logger.getLogger(NSProtocalEncoder.class);

    @SuppressWarnings("unused")
    private final Charset charset = Charset.forName("GBK");


    /**
     * 在此处实现包的编码工作,并把它写入输出流中
     */
    public void encode(IoSession session, Object message,
            ProtocolEncoderOutput out) throws Exception {
        // TODO Auto-generated method stub
        if(message instanceof BaseMessageForClient){
            BaseMessageForClient clientmessage = (BaseMessageForClient)message;
            byte[] packhead_arr = clientmessage.getPackHead().getBytes(charset);//包头2个字节
            byte[] length_arr = ByteTools.intToByteArray(clientmessage.getLength()+19, 2);//包长
            byte[] funcid_arr = ByteTools.intToByteArray(clientmessage.getFuncid(), 1);//协议类型
            byte[] packetIdCode_arr = ByteTools.longToByteArray(clientmessage.getPacketIdCode(), 8);//数据包标识码
            byte[] content_arr = clientmessage.getContent().getBytes(charset);//内容
            byte[] checkcode_arr = ByteTools.longToByteArray(clientmessage.getCheckCode(), 4);//校验码
            byte[] packtail_arr = clientmessage.getPackTail().getBytes();//包尾
            IoBuffer buffer = IoBuffer.allocate(packhead_arr.length + length_arr.length + funcid_arr.length + packetIdCode_arr.length+ content_arr.length  + checkcode_arr.length + packtail_arr.length);
            buffer.setAutoExpand(true);
            buffer.put(packhead_arr);
            buffer.put(length_arr);
            buffer.put(funcid_arr);
            buffer.put(packetIdCode_arr);
            buffer.put(content_arr);
            buffer.put(checkcode_arr);
            buffer.put(packtail_arr);
            buffer.flip();
            out.write(buffer);
            out.flush();

            buffer.free();
        }else{
            String value = (String)message;
            logger.warn("encode message:" + message);
            IoBuffer buffer = IoBuffer.allocate(value.getBytes().length);
            buffer.setAutoExpand(true);
            if(value != null){
                buffer.put(value.trim().getBytes());
            }
            buffer.flip();
            out.write(buffer);
            out.flush();

            buffer.free();
        }
    }
}

5、实现解码器ProtocolDecoder 

public class NSProtocalDecoder implements ProtocolDecoder {

    private static final Logger logger = Logger.getLogger(NSProtocalDecoder.class);
    private final AttributeKey context = new AttributeKey(getClass(), "context");
    private final Charset charset = Charset.forName("GBK");
    private final String PACK_HEAD = "$$"; //包头 
    private final String PACK_TAIL = "\r\n";  //包尾

    // 请求报文的最大长度 100k
    private int maxPackLength = 102400;

    public int getMaxPackLength() {
        return maxPackLength;
    }

    public void setMaxPackLength(int maxPackLength) {
        if (maxPackLength <= 0) {
            throw new IllegalArgumentException("请求报文最大长度:" + maxPackLength);
        }
        this.maxPackLength = maxPackLength;
    }

    private Context getContext(IoSession session) {
        Context ctx;
        ctx = (Context) session.getAttribute(context);
        if (ctx == null) {
            ctx = new Context();
            session.setAttribute(context, ctx);
        }
        return ctx;
    }

    public void decode(IoSession session, IoBuffer in, ProtocolDecoderOutput out)
            throws Exception {
        Long start = System.currentTimeMillis();
        // 报文前缀长度 包头2个字节,包长2个字节,协议类型2个字节,数据包标识码8个字节,校验码4个字节,包尾2个字节
        final int packHeadLength = 19;
        // 先获取上次的处理上下文,其中可能有未处理完的数据
        Context ctx = getContext(session);
        // 先把当前buffer中的数据追加到Context的buffer当中
        ctx.append(in);
        // 把position指向0位置,把limit指向原来的position位置
        IoBuffer buf = ctx.getBuffer();
        buf.flip();
        // 然后按数据包的协议进行读取
        while (buf.remaining() >= packHeadLength) {
            logger.debug("test 长度1:" + buf.remaining());
            buf.mark();
            // 读取包头 2个字节
            String packhead = new String(new byte[]{buf.get(),buf.get()});
            logger.debug("包头:" + packhead);
            if(PACK_HEAD.equals(packhead)){
                //读取包的长度 2个字节 报文的长度,不包含包头和包尾
                byte[] length_byte = new byte[]{buf.get(),buf.get()};
                byte[] length_byte_arr = new byte[]{0,0,0,0};
                length_byte_arr[2] = length_byte[0];
                length_byte_arr[3] = length_byte[1];
                int length = ByteTools.byteArrayToInt(length_byte_arr);
                logger.debug("长度:" + length);
                logger.debug("test 长度1:" + buf.remaining());
                // 检查读取是否正常,不正常的话清空buffer
                if (length < 0 || length > maxPackLength) {
                    logger.debug("报文长度[" + length + "] 超过最大长度:" + maxPackLength
                            + "或者小于0,清空buffer");
                    buf.clear();
                    break;
                    //packHeadLength - 2 :减去包尾的长度,
                    //length - 2 <= buf.remaining() :代表length-本身长度占用的两个字节-包头长度
                }else if(length >= packHeadLength && length - 4 <= buf.remaining()){
                    //读取协议类型2个字节
                    byte[] funcid_byte = new byte[]{buf.get()};
                    byte[] funcid_byte_arr = new byte[]{0,0,0,0};
                    //funcid_byte_arr[2] = funcid_byte[0];
                    funcid_byte_arr[3] = funcid_byte[0];
                    int funcid = ByteTools.byteArrayToInt(funcid_byte_arr);
                    logger.warn("协议类型:" + funcid);
                    //读取数据包标识码8个字节
                    byte[] packetIdCode_byte = new byte[]{buf.get(),buf.get(),buf.get(),buf.get(),buf.get(),buf.get(),buf.get(),buf.get()};
                    long packetIdCode = ByteTools.byteArrayToLong(packetIdCode_byte);
                    logger.debug("数据包标识码:" + packetIdCode);

                    //读取报文正文内容
                    int oldLimit = buf.limit();
                    logger.debug("limit:" + (buf.position() + length));
                    //当前读取的位置 + 总长度  - 前面读取的字节长度 - 校验码
                    buf.limit(buf.position() + length - 19);
                    String content = buf.getString(ctx.getDecoder());
                    buf.limit(oldLimit);
                    logger.debug("报文正文内容:" + content);
                    CRC32 crc = new CRC32();
                    crc.update(content.getBytes("GBK"));

                    //读取校验码 4个字节
                    byte[] checkcode_byte = new byte[]{buf.get(),buf.get(),buf.get(),buf.get()};
                    byte[] checkcode_byte_arr = new byte[]{0,0,0,0,0,0,0,0};
                    checkcode_byte_arr[4] = checkcode_byte[0];
                    checkcode_byte_arr[5] = checkcode_byte[1];
                    checkcode_byte_arr[6] = checkcode_byte[2];
                    checkcode_byte_arr[7] = checkcode_byte[3];
                    long checkcode = ByteTools.byteArrayToLong(checkcode_byte_arr);
                    logger.debug("校验码:" + checkcode);
                    //验证校验码
                    if(checkcode != crc.getValue()){
                        // 如果消息包不完整,将指针重新移动消息头的起始位置
                        buf.reset();
                        break;
                    }
                    //读取包尾 2个字节
                    String packtail = new String(new byte[]{buf.get(),buf.get()});
                    logger.debug("包尾:" + packtail);
                    if(!PACK_TAIL.equals(packtail)){
                        // 如果消息包不完整,将指针重新移动消息头的起始位置
                        buf.reset();
                        break;
                    }
                    BaseMessageForServer message = new BaseMessageForServer();
                    message.setLength(length);
                    message.setCheckCode(checkcode);
                    message.setFuncid(funcid);
                    message.setPacketIdCode(packetIdCode);
                    message.setContent(content);
                    out.write(message);
                }else{
                    // 如果消息包不完整,将指针重新移动消息头的起始位置
                    buf.reset();
                    break;
                }
            }else{
                // 如果消息包不完整,将指针重新移动消息头的起始位置
                buf.reset();
                break;
            }
        }
        if (buf.hasRemaining()) {
            // 将数据移到buffer的最前面
            IoBuffer temp = IoBuffer.allocate(maxPackLength).setAutoExpand(true);
            temp.put(buf);
            temp.flip();
            buf.clear();
            buf.put(temp);
        } else {// 如果数据已经处理完毕,进行清空
            buf.clear();
        }
    }

    public void finishDecode(IoSession session, ProtocolDecoderOutput out)
            throws Exception {
        // TODO Auto-generated method stub

    }

    public void dispose(IoSession session) throws Exception {
        // TODO Auto-generated method stub

    }

    // 记录上下文,因为数据触发没有规模,很可能只收到数据包的一半
    // 所以,需要上下文拼起来才能完整的处理
    private class Context {
        private final CharsetDecoder decoder;
        private IoBuffer buf;
        private int matchCount = 0;
        private int overflowPosition = 0;

        private Context() {
            decoder = charset.newDecoder();
            buf = IoBuffer.allocate(3000).setAutoExpand(true);
        }

        public CharsetDecoder getDecoder() {
            return decoder;
        }

        public IoBuffer getBuffer() {
            return buf;
        }

        @SuppressWarnings("unused")
        public int getOverflowPosition() {
            return overflowPosition;
        }

        @SuppressWarnings("unused")
        public int getMatchCount() {
            return matchCount;
        }

        @SuppressWarnings("unused")
        public void setMatchCount(int matchCount) {
            this.matchCount = matchCount;
        }

        @SuppressWarnings("unused")
        public void reset() {
            overflowPosition = 0;
            matchCount = 0;
            decoder.reset();
        }

        public void append(IoBuffer in) {
            getBuffer().put(in);
        }
    }

}

6、继承处理器IoHandlerAdapter 

public class NSMinaHandler extends IoHandlerAdapter {

    private final Logger logger = Logger.getLogger(NSMinaHandler.class);
    public static ConcurrentHashMap<Long, IoSession> sessionHashMap = new ConcurrentHashMap<Long, IoSession>();

    @Override
    public void exceptionCaught(IoSession session, Throwable cause)
            throws Exception {
        session.closeOnFlush();
        logger.error("session occured exception, so close it."
                + cause.getMessage());
    }

    @Override
    public void messageReceived(IoSession session, Object message)
            throws Exception {
        BaseMessageForServer basemessage = (BaseMessageForServer) message;
        logger.debug("客户端"
                + ((InetSocketAddress) session.getRemoteAddress()).getAddress()
                        .getHostAddress() + "连接成功!");
        session.setAttribute("type", message);
        String remoteAddress = ((InetSocketAddress) session.getRemoteAddress())
                .getAddress().getHostAddress();
        session.setAttribute("ip", remoteAddress);
        // 组装消息内容,返回给客户端
        BaseMessageForClient messageForClient = new BaseMessageForClient();
        messageForClient.setFuncid(2);
        if (basemessage.getContent().indexOf("hello") > 0) {
            // 内容
            messageForClient.setContent("hello,我收到您的消息了! ");
        } else {
            // 内容
            messageForClient.setContent("恭喜,您已经入门! ");
        }
        // 校验码生成
        CRC32 crc32 = new CRC32();
        crc32.update(messageForClient.getContent().getBytes());
        // crc校验码
        messageForClient.setCheckCode(crc32.getValue());
        // 长度
        messageForClient
                .setLength(messageForClient.getContent().getBytes().length);

        // 数据包标识码
        messageForClient.setPacketIdCode(basemessage.getPacketIdCode());
        session.write(messageForClient);
    }

    @Override
    public void messageSent(IoSession session, Object message) throws Exception {
        logger.debug("messageSent:" + message);
    }

    @Override
    public void sessionCreated(IoSession session) throws Exception {
        logger.debug("remote client [" + session.getRemoteAddress().toString()
                + "] connected.");
        Long time = System.currentTimeMillis();
        session.setAttribute("id", time);
        sessionHashMap.put(time, session);
    }

    @Override
    public void sessionClosed(IoSession session) throws Exception {
        logger.debug("sessionClosed");
        session.closeOnFlush();
        sessionHashMap.remove(session.getAttribute("id"));
    }

    @Override
    public void sessionIdle(IoSession session, IdleStatus status)
            throws Exception {
        logger.debug("session idle, so disconnecting......");
        session.closeOnFlush();
        logger.warn("disconnected");
    }

    @Override
    public void sessionOpened(IoSession session) throws Exception {
        logger.debug("sessionOpened.");
    }

}

7、实现心跳工厂KeepAliveMessageFactory 

public class NSMinaKeepAliveMessageFactory implements KeepAliveMessageFactory {

    private final Logger logger = Logger
            .getLogger(NSMinaKeepAliveMessageFactory.class);

    private BaseMessageForServer basemessage;
    /** 心跳包内容 */

    private static long packetIdCode = 0;

    /**
     * 判断是否心跳请求包 是的话返回true
     */
    public boolean isRequest(IoSession session, Object message) {
        // TODO Auto-generated method stub
        if (message instanceof BaseMessageForServer) {
            basemessage = (BaseMessageForServer) message;
            // 心跳包方法协议类型
            if (basemessage.getFuncid() == 3) {
                // 为3,代表是一个心跳包,
                packetIdCode = basemessage.getPacketIdCode();

                return true;
            } else {
                return false;
            }
        } else {
            return false;
        }
    }

    /**
     * 由于被动型心跳机制,没有请求当然也就不关注反馈 因此直接返回false
     */
    public boolean isResponse(IoSession session, Object message) {
        // TODO Auto-generated method stub
        return false;
    }

    /**
     * 被动型心跳机制无请求 因此直接返回nul
     */
    public Object getRequest(IoSession session) {
        // TODO Auto-generated method stub
        return null;
    }

    /**
     * 根据心跳请求request 反回一个心跳反馈消息
     */
    public Object getResponse(IoSession session, Object request) {
        // 组装消息内容,返回给客户端
        BaseMessageForClient messageForClient = new BaseMessageForClient();
        messageForClient.setFuncid(4);
        // 内容
        messageForClient.setContent("2222");
        // 校验码生成
        CRC32 crc32 = new CRC32();
        crc32.update(messageForClient.getContent().getBytes());
        // crc校验码
        messageForClient.setCheckCode(crc32.getValue());
        // 长度
        messageForClient
                .setLength(messageForClient.getContent().getBytes().length);

        // 数据包标识码
        messageForClient.setPacketIdCode(packetIdCode);
        return messageForClient;
    }

}

8、客户端启动

         NioSocketConnector connector = new NioSocketConnector();
        //添加过滤器
        connector.getFilterChain().addLast("logger", new LoggingFilter());
        //设置编码,解码过滤器
        connector.getFilterChain().addLast("codec", new ProtocolCodecFilter(new ByteArrayCodecFactory()));
        //connector.getFilterChain().addLast("codec", new ProtocolCodecFilter(new TextLineCodecFactory(Charset.forName("utf-8"))));//设置编码过滤器
        connector.setHandler(new ClientHandler());//设置事件处理器
        ConnectFuture cf = connector.connect(new InetSocketAddress("127.0.0.1",8888)); //建立连接
        cf.awaitUninterruptibly(); //等待连接创建完成
        BaseMessageForServer message = new BaseMessageForServer();
        String content = "hello world!";
        CRC32 crc = new CRC32();
        try {
            crc.update(content.getBytes("GBK"));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        message.setFuncid(5);
        message.setPacketIdCode(10000);
        message.setContent(content);
        message.setCheckCode(crc.getValue());
        message.setLength(content.getBytes().length);
        cf.getSession().write(message);

Mina工作流程:

当远程客户机首次访问采用Mina编写的程序时,IOAcceptor作为线程运行,负责接收来自客户的请求。当有客户请求连接时,创建一个IoSession,该IoSession与IoProcessor,SocketChannel与IoService联系起来。IoProcessor作为另一个线程运行,定时检查客户是否有数据到来,并对客户请求进行处理,一次调用IoService中注册的各个Filter,最后调用
IoHandler进行最终的逻辑处理,在将结果过滤后返回给客户端。

3个重要元素:

IoService(session:创建服务对象)<-->IoFilterChain(编码解码等)<-->IoHandler(业务处理)

IoSerivce为顶层接口,常用类:NioSocketAcceptor, NioSocketConnector

IoSession常用方法:
(1)setAttribute(Object key, Object value) getAttribute(Object key) 
功能说明:设置/获取用户定义的属性,与web应用中的session类方法setAttribute,getAttribute方法类似 
(2)getRemoteAddress() 
功能说明:获取远程客户端地址。 
(3)getId() 
功能说明:获取Session的Id 
(4)getCreationTime() 
功能说明:获得创建时间 
(5)getLastIoTime() 
功能说明:获得上次IO时间 
(6) getConfig() 
功能说明:获得配置信息。 
(7)write(Object message) 
功能说明:将数据发送给客户端。 
(8)close() 
功能说明:关闭Session。 
(说明:可以在Session中发送数据,但是Session没有提供读取数据的方法,读取数据通过解码器中的decode或者IoHandler中messageReceived方法)

IoHandler 常用方法:
(1)void exceptionCaught(IoSession session, Throwable cause) 
功能说明:有异常发生时被触发。 
(2)void messageReceived(IoSession session, Object message) 
功能说明:有消息到达时被触发,message代表接收到的消息。 
(3)void messageSent(IoSession session, Object message) 
功能说明:发送消息时时被触发,即在调用IoSession.write()时被触发,message代表将要发送的消息。 
(4)void sessionClosed(IoSession session) 
功能说明:当连接关闭时被触发,即Session终止时被触发。 
(5)void sessionCreated(IoSession session) 
功能说明:当创建一个新连接时被触发,即当开始一个新的Session时被触发。 
(6)void sessionIdle(IoSession session, IdleStatus status) 
功能说明:当连接空闲时被触发。使用IoSessionConfig中的setIdleTime(IdleStatus status, int idleTime)方法可以设置session的空闲时间。如果该Session的空闲时间超过设置的值,该方法被触发,可以通过session.getIdleCount(status)来获取sessionIdle被触发的次数。 
(7)void sessionOpened(IoSession session) 
功能说明:当打开一个连接时被触发。在目前的实现中,好像 sessionOpened 和 sessionCreated 没有太大区别,sessionCreated 在 sessionOpened 之前被触发。 

说明:IoHandler封装了来自客户端不同事件的处理,通过实现相应的方法,当该事件发生时,IoHandler中的方法就会被触发执行。 

使用示例:

//创建服务对象
IoConnector mTcpClient = new NioSocketConnector();

//添加过滤器
mTcpClient.getFilterChain().addLast(过滤器);

//public class MinaTcpClientHandler extends IoHandlerAdapter
MinaTcpClientHandler handler = new MinaTcpClientHandler(objIDCardInfoList,mHandler);

//添加处理器,一般继承IoHandlerAdapter并重写messageReceived方法用于接收新消息
mTcpClient.setHandler(handler);

//创建链接
ConnectFuture future =mTcpClient.connect(new InetSocketAddress(路径, 端口号));

// 等待连接创建完成
future.awaitUninterruptibly();

//获得session
session = future.getSession();
//写数据
session.write(strData);

if(session != null){
	session.getCloseFuture().awaitUninterruptibly();//等待连接断开
}
mTcpClient.dispose();

//-------------UDP:过滤器的生成--------------------
mUdpClient.getFilterChain().addLast("codec", new ProtocolCodecFilter(new MyProtocalCodecFactory(Charset.forName("UTF-8"))));

public class MyProtocalCodecFactory implements ProtocolCodecFactory {  
    private final JsonMessageEncoder encoder;  
    private final JsonMessageDecoder decoder;  
	//getter and setter
}

public class JsonMessageDecoder extends CumulativeProtocolDecoder {
	@Override
	protected boolean doDecode(...){}
}

断线重连:

public class ClientReconnectTest {

    public static IoSession session = null;

    public static  NioSocketConnector connector = null;

    public static void main(String[] args) {
        connector = new NioSocketConnector();
        connector.setConnectTimeoutMillis(30000); // 设置连接超时
        connector.getSessionConfig().setReceiveBufferSize(10240); // 设置接收缓冲区的大小
        connector.getSessionConfig().setSendBufferSize(10240);// 设置输出缓冲区的大小
        connector.getFilterChain().addLast("logger", new LoggingFilter());
        connector.getFilterChain().addLast("codec",
                new ProtocolCodecFilter(new ByteArrayCodecFactory()));// 设置编码过滤器
        connector.setHandler(new ClientHandler());// 设置事件处理器
        connector.setDefaultRemoteAddress(new InetSocketAddress("127.0.0.1",
                8888));// 设置默认访问地址

        // 添加重连监听---实现自动重连
        connector.addListener(new IoListener() {
            @Override
            public void sessionDestroyed(IoSession arg0) throws Exception {
                //重连10次
                for (int i= 0 ;i <= 10; i++) {
                    try {
                        Thread.sleep(3000);
                        ConnectFuture future = connector.connect();
                        future.awaitUninterruptibly();// 等待连接创建成功
                        session = future.getSession();// 获取会话
                        if (session.isConnected()) {
                            System.out.println("断线重连["
                                    + connector.getDefaultRemoteAddress()
                                            .getHostName()
                                    + ":"
                                    + connector.getDefaultRemoteAddress()
                                            .getPort() + "]成功");
                            break;
                        }
                    } catch (Exception ex) {
                        System.out.println("重连服务器登录失败,3秒再连接一次:" + ex.getMessage());
                    }
                }
            }
        });
        //确保连接成功,连接n次,
        for (int i= 0 ;i <= 5; i++) {
            try {
                ConnectFuture future = connector.connect();
                future.awaitUninterruptibly(); // 等待连接创建成功
                session = future.getSession(); // 获取会话
                if(session.isConnected()){
                    System.out.println("连接服务端"
                            + connector.getDefaultRemoteAddress()
                            .getHostName()
                            + ":"
                            + connector.getDefaultRemoteAddress()
                            .getPort()
                            + "[成功]"
                            + ",,时间:"
                            + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
                                    .format(new Date()));
                    break;
                }
            } catch (RuntimeIoException e) {
                System.out.println(
                        "连接服务端"
                                + connector.getDefaultRemoteAddress()
                                .getHostName()
                                + ":"
                                + connector.getDefaultRemoteAddress()
                                .getPort()
                                + "失败"
                                + ",,时间:"
                                + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
                                        .format(new Date())
                                + ", 连接SOCKET服务异常,请检查SOCKET端口、IP是否正确,MSG服务是否启动,异常内容:"
                                + e.getMessage());
                try {
                    Thread.sleep(5000);// 连接失败后,重连间隔5s
                } catch (InterruptedException e1) {
                    e1.printStackTrace();
                }
            }
        }

        BaseMessageForServer message = new BaseMessageForServer();
        String content = "hello world!";
        CRC32 crc = new CRC32();
        try {
            crc.update(content.getBytes("GBK"));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        message.setFuncid(5);
        message.setPacketIdCode(10000);
        message.setContent(content);
        message.setCheckCode(crc.getValue());
        message.setLength(content.getBytes().length);
        session.write(message);
    }

}

 如果对您有用的话赞一下呗!谢谢谢谢~

1 linux网络诊断命令工具_linux诊断网络故障命令(1) 12、DNS和NS查找工具14、Batfish15、Fiddler17、nload实时监控网络带宽CPU 方面内存IO 设备(磁盘、网络)网络工具mtr更多介绍 : https://mp.weixin.qq.com/s/-lru6FAhkXTo7gLCCfWlyg。 阅读详情

相关推荐

apache_mina_maven

Linux下面跑基于apache mina开源库的JAVA程序,用maven构建。详细请见http://blog.csdn.net/wuyuxing24/article/details/48500813

Apache MINA框架入门

说明 NIO API是在Java 1.4引入的。MINA是基于NIO编写的。首先要了解NIO与BIO的概念以及区别,NIO代表非阻塞IO,BIO代表着阻塞式IO。具体细节请百度。。。 MINA是一个简单但功能齐全的网络应用框架(其实已经被NettyPK掉了,但都是一类型的东西,很多东西相通的,因为我们单位在用MINA所以优先看这个)。下载地址:http://mina.apache.org/do...

DingZuoHeng的博客 2万+

68页|大型车企集团数字化转型汽车数字化信息系统平台规划方案

这份PPT文档提供了一个全面的汽车集团数字化转型规划方案,涵盖了项目目标、规划思路、实施关注点、解决方案建议以及合作优势等多个方面。

baidu_25525561的博客 1328

Mina简介

Apache的Mina(Multipurpose Infrastructure Networked Applications)是一个网络应用框架,可以帮助用户开发高性能和高扩展性的网络应用程序;它提供了一个抽象的、事件驱动的异步API,使Java NIO在各种传输协议(如TCP/IP,UDP/IP协议等)下快速高效开发。 Apache Mina也称为:     1.NIO框架     2.客

Lee的博客 1230

避坑指南:RK3588视频编码与SRT推流实战中,我遇到的5个典型问题及解决方案

本文深度解析RK3588平台视频编码与SRT推流实战中的五个典型问题,包括MIPI摄像头内存对齐、多线程数据传递、FFmpeg时间戳设置、SRT连接参数调优及系统资源监控。提供具体解决方案和优化技巧,帮助开发者高效实现实时视频网络传输。

weixin_28718793的博客 323

金融行业软件测试面试题(含答案)

6、假如发现了一个BUG,跟开发本身没什么关系,涉及到理念,需求问题,如何解决?11、假如要你测试6个月期限的p2p借款产品,你应该怎么设计案例,说出测试点。17、如果京东有一个购物网页给你,你要怎么进行测试?31、我们公司自动化测试用的语言是Java,Java你不会,该怎么办?23、你们测试用的测试环境是谁给的?24、如果领导分配你的任务超出负荷,领导高估了你的能力,怎么办。26、给你一个模块测试,只有一个星期的时间你如何有效率地完成?29、如果你组长的用例写错了,但他认为是对的,你怎么处理?

crhnb的博客 915

Apache Mina的用法

ApacheMINA是“Multipurpose Infrastructure for Network Applications”的简写,它是用于开发高性能和高可扩展性的网络应用程序的基础框架。该框架有如下优点: 1、使用该框架来开发的网络应用程序代码结构清晰明了; 2、该框架完成了底层的线程管理,省去了处理底层I/O和线程并发等复杂工作; 3、该框架内

gaohuanjie的专栏 3688

【Ultrascale+ MPSOC学习记录】10、PS端以太网使用lwip

还是参考ALINX教程,学习PS端以太网如何使用,从教程中可以看到,开发板使用了一个xilinx默认不支持的phy JL2121,所以需要修改lwip的库源码。

ryo891012的博客 880

5分钟掌握Apache MINA SSHD:Java SSH开发的终极指南

Apache MINA SSHD是一个100%纯Java库,为客户端和服务器端提供完整的SSH协议支持。无论你是需要构建SSH客户端还是嵌入SSH服务器,这个强大的工具都能让你在几分钟内快速实现功能,无需繁琐的配置过程。🚀 ## 什么是Apache MINA SSHD? Apache MINA SSHD是一个轻量级的Java SSH库,专门为需要在应用程序中集成SSH功能的开发者设计。它不旨

gitblog_00495的博客 379

【保研面试】线性代数面试复习

线性相关和无关 有向量组A,a1,a2…an , 如果存在不是全为0的k1,k2…kn,满足 a1 * k1 + a2 * k2… an * kn = 0 则向量组A称为线性相关(可以跟向量组A共面联系,即可以通过几个向量,表示出另外几个向量,故称为线性相关) 极大线性无关组 设有向量组A a1,a2…an(本身为线性相关) :若选出r个向量,满足以下条件 (1)向量组 r : 线性无关; (2) 向量组A中任意r+1个向量(若有的话)都线性相关, 则向量组r 是向量组A的一个极大线性无关组(简称为

云端筑梦师 6311

SEW MDX61B 变频器调试说明

可手动自由更改时间和地址,时间一般不更改,IP地址使用网络适配器地址(Network adapter),点击进入即可。进入网络适配器(Network adapter)后,选择适配器建议地址,点击OK,更改IP地址后点击OK。点击加载配置文件(Load a configuration),加载已保存的应用模块配置文件, 或者点击“next”,开始重新配置AMA0801模块。满足安全回路后,控制模式选为寻参模式(Reference mode),选中开始(start),即可将机械零点设置为电气零点。

xdpcxq的专栏 4301

spring boot java开发网络编程Apache Mina

springboot开发 pom.xml添加依赖 <dependency> <groupId>org.apache.mina</groupId> <artifactId>mina-integration-beans</artifactId> <version>2.0.16</version> </dependency> <dependency> <groupId&

qq_42946963的博客 7268

基于C++和Qt开发IEC104规约主站调试软件(第二章)

本章节主要讲解iec104主站软件界面设计和从站的连接功能以及部分功能代码的展示。

半青年的博客 858

交通行业809协议源码Java开发基于Apache-mina框架:项目的核心功能/场景

交通行业809协议源码Java开发基于Apache-mina框架:项目的核心功能/场景 去发现同类优质开源项目:https://gitcode.com/ 实时车辆定位接入解决方案 项目介绍 交通行业809协议源码(Java开发,基于Apache-mina框架)是一款开源的Java项目,旨在为交通管理领域提供809协议的server端主链路功能实现。通过采用Apache-mina网络通信框架,项目实...

gitblog_06796的博客 453

ABAP 平台注册 OAuth 2.0 Client 的完整实践指南(覆盖 Authorization Code、SAML Bearer 与 PKCE)

本文详述了在ABAP平台上注册入站OAuth 2.0 Client的关键技术和操作要点。文章面向SAP技术人员,系统梳理了前置条件(TLS/SSL、技术用户、授权对象)、配置路径(SOAUTH2事务)、授权类型差异(授权码、SAML Bearer、PKCE)等重要内容。特别强调入站与出站配置的区别,并提供了保密客户端和公有客户端的配置指引。文中所有事务码和参数均参考SAP官方文档,包含多个实用案例和权限配置建议,为ABAP系统作为OAuth 2.0授权服务器的实施提供全面指导。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 297

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

3步掌握Apache MINA SSHD:Java SSH服务开发终极指南

Apache MINA SSHD是一个100%纯Java的SSH协议库,支持客户端和服务器端的SSH功能开发。这个强大的开源项目让Java开发者能够轻松构建SSH客户端和服务器应用,无需依赖系统级SSH工具。无论你是需要为应用添加远程访问功能,还是构建自动化运维工具,Apache MINA SSHD都能提供完整的解决方案。 ## 🚀 快速开始:5分钟搭建SSH服务器 Apache MINA

gitblog_00706的博客 437

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

java mina聊天_apache Mina开发实现多人聊天室程序命令行版本

package com.zuidaima.mina.server;import java.io.IOException;import java.net.InetSocketAddress;import org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder;import org.apache.mina.core.session.Id...

weixin_35810223的博客 199

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

JAVA网络服务器框架 - apache mina

apache 发布的一个java服务器开发框架,通过装配不同的协议,快速实现一些网络服务器,通过AsyncWeb和apache httpd测试比较发现,性能相差无几。 参考网页: 2, http://www.ibm.com/developerworks/cn/opensource/os-cn-apmina/ 1, http://mina.apache.org/

开心乐源的专栏 1030

[MINA]使用 Apache MINA 开发高性能网络应用程序

简介: 本文将通过一个简单的问候程序 HelloServer 来介绍 MINA 的基础架构的同时演示如何使用 MINA 开发网络应用程序。 Netty 是JBoss旗下的io传输的框架,他利用java里面的nio来实现高效,稳定的io传输。 Apache MINA(Multipurpose Infrastructure for Network Applications) 是 Apach

九头鹰 1570

Apache MINA SSHD

Apache MINA SSHD(Secure Shell Daemon)是基于Apache MINA(Multipurpose Infrastructure for Network Applications)开发的一个开源的Java库,专门用于提供SSH(Secure Shell)服务。

m0_37559973的博客 2437

java mina框架_如何搭建高性能Java网络框架 MINA

1.介绍Apache MINA 是一个网络应用框架,有助于用户非常方便地开发高性能、高伸缩性的网络应用。它通过Java NIO提供了一个抽象的、事件驱动的、异步的位于各种传输协议(如TCP/IP和UDP/IP)之上的API,Apache MINA 通常可被称之为:NIO 框架库;客户端/服务器框架库;或者一个网络socket库。然而,它所提供的功能远不止这些。(以上内容大致翻译自Apache MI...

weixin_42451196的博客 550

Apache MINA 开发高性能网络应用程序

<br />本文将通过一个简单的问候程序 HelloServer 来介绍 MINA 的基础架构的同时演示如何使用 MINA 开发网络应用程序。<br />Apache MINA(Multipurpose Infrastructure for Network Applications) 是 Apache 组织一个较新的项目,它为开发高性能和高可用性的网络应用程序提供了非常便利的框架。当前发行的 MINA 版本支持基于 Java NIO 技术的 TCP/UDP 应用程序开发、串口通讯程序(只在最新的预览版中提供

stulingyu的专栏 500

【Apache-Mina】一:使用Mina实现“HelloWorld”

文章目录前言一、Apache-Mina是什么?二、使用步骤1.服务端2.业务实现类 Handler3.调试运行总结参考资料 & 致谢 前言 提示:这里可以添加本文要记录的大概内容: 例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。 一、Apache-Mina是什么? Apache Mina是一个能够帮助用户开发高性能和高伸缩性网络应用程序的框架。它通过Java nio技术基于TCP/IP和UDP/IP协议提供了抽象的、事件

OxYGC 619

java应用服务框架_java 应用服务框架mina和netty应用

java应用服务框架mina和netty应用Netty是由JBOSS提供的一个java开源框架。Netty提供异步的、事件驱动的网络应用程序框架和工具,用以快速开发高性能、高可靠性的网络服务器和客户端程序。Netty 是一个基于NIO的客户,服务器端编程框架,使用Netty可以确保你快速和简单的开发出一个网络应用,例如实现了某种协议的客户,服务端应用。Netty相当简化和流线化了网络应用的编程开发...

weixin_29666341的博客 254

Apache MINA框架

Apache MINA(Multipurpose Infrastructure for Network Applications) 是 Apache 组织一个较新的项目,它为开发高性能和高可用性的网络应用程序提供了非常便利的框架。当前发行的 MINA 版本支持基于 Java NIO 技术的 TCP/UDP 应用程序开发、串口通讯程序(只在最新的预览版中提供),MINA 所支持的功能也在进一步的扩展

polo_longsan的专栏 645

java 著名的应用程序_基于Java NIO的两个著名的网络应用程序开发库Mina和Netty

基于Java NIO的两个著名的网络程序开发库Mina和NettyMina:来自Apache社区。先摘一点在这里,有空了研究。Apache MINA is a network application framework which helps users develop high performance and high scalability network applications easil...

weixin_31230841的博客 111
上一篇: 创建有返回值的线程(Callable+FutureTask)
下一篇: java开发——enum枚举单例的使用
river66
博客等级 码龄8年 76粉丝 108原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值