mina现在用的很多了,之前也有用到,但是毕竟不熟悉,于是查了一些资料,做了一些总结。看代码是最直观的,比什么长篇大论都要好。不过其中重要的理论,也要理解下。
首先是环境,程序运行需要几个包,这里用maven比较方便。
pom.xml:
4.0.0 MyMinaServer mina 0.0.1-SNAPSHOT jar mina http://maven.apache.org UTF-8 org.apache.mina mina-core 2.0.4 org.slf4j jcl-over-slf4j 1.6.1 org.slf4j slf4j-nop 1.6.1 junit junit 3.8.1 test
然后就可以写代码了。
---------------------------------------------------------- 分割线 -----------------------------------------------------------------------------------------
一,简单的客户端和服务端程序
服务端程序:
package MyMinaServer.mina;import java.io.IOException;import java.net.InetSocketAddress;import java.nio.charset.Charset;import org.apache.mina.core.service.IoAcceptor;import org.apache.mina.core.session.IdleStatus;import org.apache.mina.filter.codec.ProtocolCodecFilter;import org.apache.mina.filter.codec.textline.TextLineCodecFactory;import org.apache.mina.filter.logging.LoggingFilter;import org.apache.mina.transport.socket.nio.NioSocketAcceptor;public class MainServer { private static final int Port=8888; public static void main(String[] args) { IoAcceptor ioAcceptor=new NioSocketAcceptor(); System.out.println("begin server...."); ioAcceptor.getFilterChain().addLast("logger", new LoggingFilter()); ioAcceptor.getFilterChain().addLast("codec", new ProtocolCodecFilter(new TextLineCodecFactory(Charset.forName("UTF-8")))); ioAcceptor.setHandler(new HelloWorldHandler()); ioAcceptor.getSessionConfig().setReadBufferSize(2048); ioAcceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 10); try { ioAcceptor.bind(new InetSocketAddress(Port)); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } }}
服务端,创建连接,然后这里注册了几个过滤链,这里简单写了需要的两个,到后面的内容中还可以加入一个加密的ssl链。
其中重要的是setHandler这个,在这个里面,我们可以定义自己的handler,然后做自己的业务。下面有这个handler的简单代码。
最后设置session的缓冲,和idle(空闲处理)的设定,再为此连接绑定一个端口。
其中需要注意的是,在服务端和客户端的代码里面,如果要传递string信息,codec编码过滤器中,要这么写:new ProtocolCodecFilter(new TextLineCodecFactory(Charset.forName("UTF-8")))。否则报错。
业务处理的handler:
package MyMinaServer.mina;import org.apache.mina.core.service.IoHandlerAdapter;import org.apache.mina.core.session.IdleStatus;import org.apache.mina.core.session.IoSession;public class HelloWorldHandler extends IoHandlerAdapter{ @Override public void exceptionCaught(IoSession session, Throwable cause) throws Exception { // TODO Auto-generated method stub super.exceptionCaught(session, cause); } @Override public void messageReceived(IoSession session, Object message) throws Exception { // TODO Auto-generated method stub String string=message.toString(); if (string.trim().equalsIgnoreCase("quit")) { session.close(true); return; } System.out.println("recevied message:"+string); String reply=" hi, i am server"; session.write(reply); System.out.println("message have been written"); } @Override public void messageSent(IoSession session, Object message) throws Exception { // TODO Auto-generated method stub System.out.println("message have been sent"); } @Override public void sessionClosed(IoSession session) throws Exception { // TODO Auto-generated method stub System.out.println("closed session"); } @Override public void sessionCreated(IoSession session) throws Exception { // TODO Auto-generated method stub System.out.println("session created"); } @Override public void sessionIdle(IoSession session, IdleStatus status) throws Exception { // TODO Auto-generated method stub System.out.println("IDLE "+session.getIdleCount(status)); } @Override public void sessionOpened(IoSession session) throws Exception { // TODO Auto-generated method stub System.out.println("session opened"); }}
这里的每个方法,算是事件。在每个事件中,我们可以定义自己的处理。在前面的《》这篇文章中,笔者曾写过他们的每个事件代表的含义,不过从字面意思也很好理解。
这里主要是对接受到信息的处理,如果不是收到quit字符,则返回给客户端一句 hi,i am server。
服务端暂时到此,以下是客户端。
package com.example.mina.server;import java.net.InetSocketAddress;import java.nio.charset.Charset;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.session.IoSession;import org.apache.mina.filter.codec.ProtocolCodecFilter;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 com.example.mina.charset.CharsetFactory;import com.example.mina.hanlder.MsgHanler;public class MinaClient { private SocketConnector connector; private ConnectFuture future; private IoSession session; public boolean connect() { /* * 1.创建一个socket连接,连接到服务器 */ connector = new NioSocketConnector(); /* * 获取过滤器链,用于添加过滤器 */ DefaultIoFilterChainBuilder chain = connector.getFilterChain(); // b.添加日志过滤器 chain.addLast("logger", new LoggingFilter()); // c.添加字符的编码过滤器 chain.addLast("codec", new ProtocolCodecFilter(new TextLineCodecFactory(Charset.forName("UTF-8")))); /* * 3.设置消息处理器,用于处理接收到的消息 */ connector.setHandler(new MsgHanler()); /* * 4.根据IP和端口号连接到服务器 */ future = connector.connect(new InetSocketAddress("127.0.0.1", 8888)); // 等待连接创建完成 future.awaitUninterruptibly(); /* * 5.获取session对象,通过session可以向服务器发送消息; */ session = future.getSession(); session.getConfig().setUseReadOperation(true); return future.isConnected(); } /** * 往服务器发送消息 * * @param message */ public void sendMsg2Server(String message) { session.write(message); } /** * 关闭与服务器的连接 * * @return */ public boolean close() { CloseFuture future = session.getCloseFuture(); future.awaitUninterruptibly(1000); connector.dispose(); return true; }}
然后同样是一个客户端的handler,和server的很像:
package com.example.mina.hanlder;import org.apache.mina.core.service.IoHandlerAdapter;import org.apache.mina.core.session.IoSession;import org.slf4j.Logger;import org.slf4j.LoggerFactory;public class MsgHanler extends IoHandlerAdapter { private static final Logger log = LoggerFactory.getLogger(MsgHanler.class); @Override public void exceptionCaught(IoSession session, Throwable cause) throws Exception { // 出现异常 log.error("--------exception--------"); super.exceptionCaught(session, cause); } @Override public void messageReceived(IoSession session, Object message) throws Exception { // 从服务器中接收到消息后的处理 log.info("--------msg receive--------"); log.info("Message:{}" + message.toString()); super.messageReceived(session, message); } @Override public void messageSent(IoSession session, Object message) throws Exception { // 往服务器中发送消息 log.info("--------msg sent--------"); super.messageSent(session, message); } @Override public void sessionCreated(IoSession session) throws Exception { // 当session被创建的时候调用 log.info("--------session create--------"); super.sessionCreated(session); }}
写一个入口方法:
package com.example.mina.server;public class Main { public static void main(String[] args) { MinaClient client=new MinaClient(); client.connect(); client.sendMsg2Server("message from cilent"); }}
这样,客户端就可以工作了。
先启动服务端,然后启动客户端,就可以看到在两个控制台中,分别有交互信息。
服务端:
begin server....
session createdsession openedrecevied message:message from cilentmessage have been writtenmessage have been sent客户端:
[QC] INFO [NioProcessor-2] org.apache.mina.filter.logging.LoggingFilter.log(186) | CREATED
[QC] INFO [NioProcessor-2] com.example.mina.hanlder.MsgHanler.sessionCreated(54) | --------session create--------[QC] INFO [NioProcessor-2] org.apache.mina.filter.logging.LoggingFilter.log(186) | OPENED[QC] INFO [NioProcessor-2] org.apache.mina.filter.logging.LoggingFilter.log(157) | SENT: HeapBuffer[pos=0 lim=0 cap=0: empty][QC] INFO [NioProcessor-2] com.example.mina.hanlder.MsgHanler.messageSent(47) | --------msg sent--------[QC] INFO [NioProcessor-2] org.apache.mina.filter.logging.LoggingFilter.log(157) | RECEIVED: HeapBuffer[pos=0 lim=17 cap=2048: 20 68 69 2C 20 69 20 61 6D 20 73 65 72 76 65 72...][QC] INFO [NioProcessor-2] com.example.mina.hanlder.MsgHanler.messageReceived(39) | --------msg receive--------[QC] INFO [NioProcessor-2] com.example.mina.hanlder.MsgHanler.messageReceived(40) | Message:{} hi, i am server客户端因为用了log4j,打印比较多信息。
到此,这个例子就完成了。