初识Mina,简要记录理解内容和实现demo。
这里先简述一下BIO和NIO的区别:
同步阻塞IO(BIO):一个连接一个线程,客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销,可以通过线程池机制改善。
同步非阻塞IO(NIO):一个请求一个线程,客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有I/O请求时才启动一个线程进行处理。
异步阻塞IO(AIO):一个有效请求一个线程,客户端的I/O请求都是由OS先完成了再通知服务器应用去启动线程进行处理。
Mina定义:
Apache Mina是一个能够帮助用户开发高性能和高伸缩性网络应用程序的框架。它通过Java nio技术基于TCP/IP和UDP/IP协议提供了抽象的、事件驱动的、异步的API。
Mina好处:
NIO基于事件驱动思想,主要解决BIO的高并发问题(当多客户端请求服务器时每一个连接都需要启动一个线程来单独进行处理,而内存是有限的,当客户端数大到一定程度时候即便是使用线程池也无法解决内存有限和OS自身对线程数的限制带来的问题),但是NIO的复杂让很多开发人员感到痛苦,所以诞生了Mina框架,让我们可以不必考虑如何实现NIO方案,直接使用Mina即可快速进行网络编程。(注:Mina还支持多协议通信)
Mina的接口:
IoService:mina请求接受器(IoAcceptor)以及连接器(IoConnector)的一个抽象的父类,作用就是提供连接和接受请求的服务(封装了IO操作,不需要自己实现异步和线程,直接使用就可以了)。
IoProcessor:请求处理器,拥有自己的Selector,负责请求的处理工作,包括监听事件的更改,filterChain的建立,响应事件的调用(sessionCreated、sessionOpened、messageRecieved等)以及IO读写操作。
IoFilter:过滤器,不多解释,数据的encode 与decode是我们最需要关注的。
IoHandler:负责编写业务逻辑,也就是接收、发送数据的接口,开发者自己实现该接口,做逻辑处理。
工作流程:
(1)创建IoService
(2)添加过滤器/拦截器IoFilterChain
(3)实现IoHandler对数据进行业务逻辑处理
不啰嗦直接上代码,代码中会有注释:
服务端:
/** * @author huangzhang * @description * @date Created in 2018/7/17 11:46 */ public class MyServer { public static void main(String[] args) throws Exception{ // 新建acceptor:服务端 IoAcceptor ioAcceptor = new NioSocketAcceptor(); //设置读取数据缓冲区大小 ioAcceptor.getSessionConfig().setReadBufferSize(2048); //指定了什么时候检查空闲 session ioAcceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE,10); //设定消息编码规则拦截器 ioAcceptor.getFilterChain().addLast("codec", new ProtocolCodecFilter(new TextLineCodecFactory())); //设置Handler ioAcceptor.setHandler(new ServerHandler()); ioAcceptor.bind(new InetSocketAddress(8080)); } }
服务端handler:
/** * @author huangzhang * @description * @date Created in 2018/7/17 11:52 */ public class ServerHandler extends IoHandlerAdapter { private final Logger logger = LoggerFactory.getLogger(ServerHandler.class); @Override public void sessionCreated(IoSession session) throws Exception { System.out.println(" Server session created"); } @Override public void sessionOpened(IoSession session) throws Exception { System.out.println(" Server connection succeed"); } @Override public void sessionClosed(IoSession session) throws Exception { System.out.println(" Server session closed"); } @Override public void sessionIdle(IoSession session, IdleStatus status) throws Exception { System.out.println(" Server session idle"); } @Override public void exceptionCaught(IoSession session, Throwable cause) throws Exception { System.out.println(" Server caught:"+cause); } @Override public void messageReceived(IoSession session, Object message) throws Exception { String str = message.toString(); logger.info("The message received is [ "+ str +"]"); if (str.endsWith("quit")){ session.close(true); return; } session.write("啦啦啦" + message); } }
客户端:
/** * @author huangzhang * @description * @date Created in 2018/7/17 12:08 */ public class ClientHandler extends IoHandlerAdapter { @Override public void sessionOpened(IoSession session) throws Exception { System.out.println("Client connection succeed"); } @Override public void sessionClosed(IoSession session) throws Exception { System.out.println("Client connection closed"); } @Override public void sessionIdle(IoSession session, IdleStatus status) throws Exception { System.out.println("Client connection idle"); } @Override public void exceptionCaught(IoSession session, Throwable cause) throws Exception { System.out.println("Client caught:"+ cause); } @Override public void messageReceived(IoSession session, Object message) throws Exception { System.out.println("Client received :"+ message.toString()); } @Override public void messageSent(IoSession session, Object message) throws Exception { System.out.println("Client send:"+ message); } }
客户端handler:
/** * @author huangzhang * @description * @date Created in 2018/7/17 12:04 */ public class MyClient { public static void main(String[] args) { //建立一个connector IoConnector ioConnector = new NioSocketConnector(); //设置连接超时时间 ioConnector.setConnectTimeoutMillis(2000); //设置编码过滤器 ioConnector.getFilterChain().addLast("codec", new ProtocolCodecFilter(new TextLineCodecFactory())); //设置消息处理handler ioConnector.setHandler(new ClientHandler()); //连接服务器 ConnectFuture future = ioConnector.connect(new InetSocketAddress("localhost",8080)); //阻塞直至连接成功 future.awaitUninterruptibly(); //client从控制台输入内容 BufferedReader bufferedReader = null; try{ bufferedReader = new BufferedReader(new InputStreamReader(System.in,"UTF-8")); String string; while (!(string = bufferedReader.readLine()).equals("exit")){ future.getSession().write("客户端发送消息:"+ string); } }catch (IOException e){ e.printStackTrace(); } } }
先运行服务端,启动服务,然后运行客户端,与服务端建立连接,然后通信(客户端发送消息是从控制台输入的)。