Mina框架的使用[通俗易懂]

2022-08-01 12:09:38 浏览数 (1)

大家好,又见面了,我是你们的朋友全栈君。

什么是Mina框架

代码语言:javascript复制
Apache Mina是一个能够帮助用户开发高性能和高伸缩性网络应用程序的框架。它通过Java nio技术基于TCP/IP和UDP/IP协议提供了抽象的、事件驱动的、异步的API。是用来代替
NIO网络框架的,对NIO框架进行了一层封装的Socket库。

Mina主页 下载地址

为什么使用Mina?

传统socket:阻塞式通信

每建立一个Socket连接时,同时创建一个新线程对该Socket进行单独通信(采用阻塞的方式通信)。这种方式具有很高的响应速度,并且控制起来也很简单,在连接数较少的时候非常有效,但是如果对每一个连接都产生一个线程的无疑是对系统资源的一种浪费,如果连接数较多将会出现资源不足的情况。

nio:非阻塞通信

nio设计背后的基石:反应器模式,用于事件多路分离和分派的体系结构模式。

反应器模式的核心功能如下: 将事件多路分用 将事件分派到各自相应的事件处理程序

NIO 的非阻塞 I/O 机制是围绕 选择器和 通道构建的。Channel 类表示服务器和客户机之间的一种通信机制。Selector 类是 Channel 的多路复用器。 Selector 类将传入客户机请求多路分用并将它们分派到各自的请求处理程序。

通道(Channel 类):表示服务器和客户机之间的一种通信机制。 选择器(Selector类):是 Channel 的多路复用器。

Selector 类将传入的客户机请求多路分用并将它们分派到各自的请求处理程序。

简单的来说:NIO是一个基于事件的IO架构。 最基本的思想就是:有事件我通知你,你再去做你的事情。而且NIO的主线程只有一个,不像传统的模型,需要多个线程以应对客户端请求,也减轻了JVM的工作量。

当Channel注册至Selector以后,经典的调用方法如下:nio中取得事件通知,就是在selector的select事件中完成的。在selector事件时有一个线程向操作系统询问,selector中注册的Channel&&SelectionKey的键值对的各种事件是否有发生,如果有则添加到selector的selectedKeys属性Set中去,并返回本次有多少个感兴趣的事情发生。如果发现这个值>0,表示有事件发生,马上迭代selectedKeys中的SelectionKey,根据Key中的表示的事件,来做相应的处理。实际上,这段说明表明了异步socket的核心,即异步socket不过是将多个socket的调度(或者还有他们的线程调度)全部交给操作系统自己去完成,异步的核心Selector,不过是将这些调度收集、分发而已。

传统的socket实现C/S通讯 服务端

代码语言:javascript复制
public class SocketServer {
    public static void main(String[] args) {
        SocketServer ss = new SocketServer();
        ss.startServer();
    }

    public void startServer() {
        ServerSocket serverSocket;
        Socket socket;
        BufferedReader reader;
        BufferedWriter writer;
        try {
            // new一个socket对象并且设置端口号
            serverSocket = new ServerSocket(9898);
            System.out.println("服务器打开了");
            socket = serverSocket.accept();
            System.out.println("client"   socket.hashCode()   "connect");
            reader = new BufferedReader(new InputStreamReader(
                    socket.getInputStream()));
            writer = new BufferedWriter(new OutputStreamWriter(
                    socket.getOutputStream()));
            String recevierMsg;
            while ((recevierMsg = reader.readLine()) != null) {
                System.out.println(recevierMsg   "11");
                writer.write(recevierMsg "response");
            }

        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

流我没有关,代码很繁琐而且当多个客户端连入也没有处理 那让我们看看使用mina建的客户端

代码语言:javascript复制
public class MinaSocket {
    public static void main(String[] args) {
        try {
            NioSocketAcceptor acceptor = new NioSocketAcceptor();
            acceptor.setHandler(new MyserverHandler());
            acceptor.getFilterChain().addLast("code", new ProtocolCodecFilter(new TextLineCodecFactory()));// 过滤
            acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 5000);
            acceptor.bind(new InetSocketAddress(8989));
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }
}

仅需要4不即可完成 在MyserverHandler写消息处理的代码

代码语言:javascript复制
import java.awt.datatransfer.StringSelection;

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

/** * 专门用来处理消息收发的类 * * @author Jay-Tang * */
public class MyserverHandler extends IoHandlerAdapter { 
   

    @Override
    public void exceptionCaught(IoSession session, Throwable cause)
            throws Exception {
        // TODO Auto-generated method stub
        super.exceptionCaught(session, cause);
        System.out.println("exceptionCaught");
    }
//收到消息
    @Override
    public void messageReceived(IoSession session, Object message)
            throws Exception {
        // TODO Auto-generated method stub
        super.messageReceived(session, message);
        String s = (String) message;
        System.out.println(s);
        session.write("server reply" s);
    }

    @Override
    public void messageSent(IoSession session, Object message) throws Exception {
        // TODO Auto-generated method stub
        super.messageSent(session, message);

        System.out.println("messageSent");

    }

    @Override
    public void sessionClosed(IoSession session) throws Exception {
        // TODO Auto-generated method stub
        super.sessionClosed(session);
        System.out.println("sessionClosed");
    }

    @Override
    public void sessionCreated(IoSession session) throws Exception {
        // TODO Auto-generated method stub
        super.sessionCreated(session);
        System.out.println("sessionCreated");
    }

    @Override
    public void sessionIdle(IoSession session, IdleStatus status)
            throws Exception {
        // TODO Auto-generated method stub
        super.sessionIdle(session, status);
        System.out.println("sessionIdle");
    }

    @Override
    public void sessionOpened(IoSession session) throws Exception {
        // TODO Auto-generated method stub
        super.sessionOpened(session);
        System.out.println("sessionOpened");
    }

}

从每个方法的名称就可以看出其要实现的功能 传统的Socket客户端代码

代码语言:javascript复制
public class SocketClient {
    public static void main(String[] args) {
        SocketClient client = new SocketClient();
        client.start();
    }

    public void start() {
        BufferedReader inputReader = null;
        BufferedReader reader = null;
        BufferedWriter writer = null;
        Socket socket = null;
        try {
            socket = new Socket("127.0.0.1", 8989);
            reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
            inputReader = new BufferedReader(new InputStreamReader(System.in));
            startServerReplyListener(reader);
            String inputContent;
            int count = 0;
            while (!(inputContent = inputReader.readLine()).equals("bye")) {
                writer.write(inputContent);
                if (count % 2 ==0) {
                    writer.write("n");
                }
                count  ;
                writer.flush();
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                reader.close();
                writer.close();
                inputReader.close();
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public void startServerReplyListener(final BufferedReader reader) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    String response;
                    while ((response = reader.readLine()) != null) {
                        System.out.println(response);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

}

再来看看mina写的客户端

代码语言:javascript复制
//客户端使用mina
public class MinaClient {
public static void main(String[] args) throws Exception{
NioSocketConnector connector=new    NioSocketConnector();
connector.setHandler(new MyclientrHandler());
connector.getFilterChain().addLast("codec", new ProtocolCodecFilter(new  TextLineCodecFactory()));
ConnectFuture futrue=connector.connect(new InetSocketAddress("127.0.0.1",8989));
futrue.awaitUninterruptibly();
IoSession ioSession=futrue.getSession();
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String inputContent;
while(!(inputContent=reader.readLine()).equals("bye")){
    ioSession.write(inputContent);


}
}
}

也只需要四部 ,再写一个MyclientrHandler实现功能 代码与服务端的handler相似

代码语言:javascript复制
//客户端使用mina
public class MinaClient {
public static void main(String[] args) throws Exception{
NioSocketConnector connector=new    NioSocketConnector();
connector.setHandler(new MyclientrHandler());
connector.getFilterChain().addLast("codec", new ProtocolCodecFilter(new  TextLineCodecFactory()));
ConnectFuture futrue=connector.connect(new InetSocketAddress("127.0.0.1",8989));
futrue.awaitUninterruptibly();
IoSession ioSession=futrue.getSession();
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String inputContent;
while(!(inputContent=reader.readLine()).equals("bye")){
    ioSession.write(inputContent);


}
}
}

这是简单使用mina建立客户端和服务端的操作 都是使用TextLineCodecFactory()实现解码,其实还可以自己一个工厂类MyTextLineCodecFactory来继承ProtocolCodecFactory ~ 这里就不提到了。。。

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/126543.html原文链接:https://javaforall.cn

0 人点赞