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
然后就可以写代码了。
---------------------------------------------------------- 分割线 -----------------------------------------------------------------------------------------
一,简单的客户端和服务端程序
服务端程序:
packageMyMinaServer.mina;importjava.io.IOException;importjava.net.InetSocketAddress;importjava.nio.charset.Charset;importorg.apache.mina.core.service.IoAcceptor;importorg.apache.mina.core.session.IdleStatus;importorg.apache.mina.filter.codec.ProtocolCodecFilter;importorg.apache.mina.filter.codec.textline.TextLineCodecFactory;importorg.apache.mina.filter.logging.LoggingFilter;importorg.apache.mina.transport.socket.nio.NioSocketAcceptor;public classMainServer {private static final int Port=8888;public static voidmain(String[] args) {
IoAcceptor ioAcceptor=newNioSocketAcceptor();
System.out.println("begin server....");
ioAcceptor.getFilterChain().addLast("logger", newLoggingFilter());
ioAcceptor.getFilterChain().addLast("codec", new ProtocolCodecFilter(new TextLineCodecFactory(Charset.forName("UTF-8"))));
ioAcceptor.setHandler(newHelloWorldHandler());
ioAcceptor.getSessionConfig().setReadBufferSize(2048);
ioAcceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE,10);try{
ioAcceptor.bind(newInetSocketAddress(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:
packageMyMinaServer.mina;importorg.apache.mina.core.service.IoHandlerAdapter;importorg.apache.mina.core.session.IdleStatus;importorg.apache.mina.core.session.IoSession;public class HelloWorldHandler extendsIoHandlerAdapter{
@Overridepublic voidexceptionCaught(IoSession session, Throwable cause)throwsException {//TODO Auto-generated method stub
super.exceptionCaught(session, cause);
}
@Overridepublic voidmessageReceived(IoSession session, Object message)throwsException {//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");
}
@Overridepublic void messageSent(IoSession session, Object message) throwsException {//TODO Auto-generated method stub
System.out.println("message have been sent");
}
@Overridepublic void sessionClosed(IoSession session) throwsException {//TODO Auto-generated method stub
System.out.println("closed session");
}
@Overridepublic void sessionCreated(IoSession session) throwsException {//TODO Auto-generated method stub
System.out.println("session created");
}
@Overridepublic voidsessionIdle(IoSession session, IdleStatus status)throwsException {//TODO Auto-generated method stub
System.out.println("IDLE "+session.getIdleCount(status));
}
@Overridepublic void sessionOpened(IoSession session) throwsException {//TODO Auto-generated method stub
System.out.println("session opened");
}
}
这里的每个方法,算是事件。在每个事件中,我们可以定义自己的处理。在前面的《AndroidPn源码分析(一)》这篇文章中,笔者曾写过他们的每个事件代表的含义,不过从字面意思也很好理解。
这里主要是对接受到信息的处理,如果不是收到quit字符,则返回给客户端一句 hi,i am server。
服务端暂时到此,以下是客户端。
packagecom.example.mina.server;importjava.net.InetSocketAddress;importjava.nio.charset.Charset;importorg.apache.mina.core.filterchain.DefaultIoFilterChainBuilder;importorg.apache.mina.core.future.CloseFuture;importorg.apache.mina.core.future.ConnectFuture;importorg.apache.mina.core.session.IoSession;importorg.apache.mina.filter.codec.ProtocolCodecFilter;importorg.apache.mina.filter.codec.textline.TextLineCodecFactory;importorg.apache.mina.filter.logging.LoggingFilter;importorg.apache.mina.transport.socket.SocketConnector;importorg.apache.mina.transport.socket.nio.NioSocketConnector;importcom.example.mina.charset.CharsetFactory;importcom.example.mina.hanlder.MsgHanler;public classMinaClient {privateSocketConnector connector;privateConnectFuture future;privateIoSession session;public booleanconnect() {/** 1.创建一个socket连接,连接到服务器*/connector= newNioSocketConnector();/** 获取过滤器链,用于添加过滤器*/DefaultIoFilterChainBuilder chain=connector.getFilterChain();//b.添加日志过滤器
chain.addLast("logger", newLoggingFilter());//c.添加字符的编码过滤器
chain.addLast("codec", new ProtocolCodecFilter(new TextLineCodecFactory(Charset.forName("UTF-8"))));/** 3.设置消息处理器,用于处理接收到的消息*/connector.setHandler(newMsgHanler());/** 4.根据IP和端口号连接到服务器*/future= connector.connect(new InetSocketAddress("127.0.0.1", 8888));//等待连接创建完成
future.awaitUninterruptibly();/** 5.获取session对象,通过session可以向服务器发送消息;*/session=future.getSession();
session.getConfig().setUseReadOperation(true);returnfuture.isConnected();
}/*** 往服务器发送消息
*
*@parammessage*/
public voidsendMsg2Server(String message) {
session.write(message);
}/*** 关闭与服务器的连接
*
*@return
*/
public booleanclose() {
CloseFuture future=session.getCloseFuture();
future.awaitUninterruptibly(1000);
connector.dispose();return true;
}
}
然后同样是一个客户端的handler,和server的很像:
packagecom.example.mina.hanlder;importorg.apache.mina.core.service.IoHandlerAdapter;importorg.apache.mina.core.session.IoSession;importorg.slf4j.Logger;importorg.slf4j.LoggerFactory;public class MsgHanler extendsIoHandlerAdapter {private static final Logger log = LoggerFactory.getLogger(MsgHanler.class);
@Overridepublic voidexceptionCaught(IoSession session, Throwable cause)throwsException {//出现异常
log.error("--------exception--------");super.exceptionCaught(session, cause);
}
@Overridepublic voidmessageReceived(IoSession session, Object message)throwsException {//从服务器中接收到消息后的处理
log.info("--------msg receive--------");
log.info("Message:{}" +message.toString());super.messageReceived(session, message);
}
@Overridepublic void messageSent(IoSession session, Object message) throwsException {//往服务器中发送消息
log.info("--------msg sent--------");super.messageSent(session, message);
}
@Overridepublic void sessionCreated(IoSession session) throwsException {//当session被创建的时候调用
log.info("--------session create--------");super.sessionCreated(session);
}
}
写一个入口方法:
packagecom.example.mina.server;public classMain {public static voidmain(String[] args) {
MinaClient client=newMinaClient();
client.connect();
client.sendMsg2Server("message from cilent");
}
}
这样,客户端就可以工作了。
先启动服务端,然后启动客户端,就可以看到在两个控制台中,分别有交互信息。
服务端:
begin server....
session created
session opened
recevied message:message from cilent
message have been written
message 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,打印比较多信息。
到此,这个例子就完成了。