应用场景:目前开发的一个项目全部使用的tcp通信,我们自己的手机端作为服务端,我们另一款软件是安装到电脑上作为客户端与我们这边进行通信(我们这边实现的端对端的隧道模式,数据并不经过其他地方),涉及到登录包回复,心跳包回复,客户端下线通知,以及我们的各种指令去获取客户端的数据.这个项目的通信框架就是使用的mina,本文主要的作用是让大家能在最短的时间内应用上mina框架 (到底有多短,是真的很短啊),mina具体的内部实现原理另外说明.
相信大家都知道,首先我们作为服务端只用开启一个端口等着客户端来连就行了,在mina中我们如何开启呢:我们可以新建一个MonServer的类代码如下
public class MonServer {
private SocketAcceptoracceptor;
public MonServer() {
acceptor =new NioSocketAcceptor();
}
public boolean start() {
DefaultIoFilterChainBuilder filterChain =acceptor.getFilterChain();
filterChain.addLast("codec", new ProtocolCodecFilter(new CharsetCodecFactory()));//指定编码解码器工厂
LoggingFilter loggingFilter =new LoggingFilter();
loggingFilter.setMessageReceivedLogLevel(LogLevel.INFO);
loggingFilter.setMessageSentLogLevel(LogLevel.INFO);
filterChain.addLast("loger", loggingFilter);
try {
acceptor.setHandler(new ServerMessageHandler()); //指定我们消息处理的handler
}catch (IOException e1) {
e1.printStackTrace();
return false;
}
acceptor.getSessionConfig().setIdleTime(IdleStatus.READER_IDLE, 1000);//指定读取的超时时间
try {
acceptor.bind(new InetSocketAddress(9026));//指定端口
}catch (IOException e) {
e.printStackTrace();
return false;
}
return true;
}
}
我们看到在这里面有两个类是mina没有的,CharsetCodecFactory和ServerMessageHandler,注释已经写得很清楚了,我们先看下这个CharsetCodecFactory类是什么
public class CharsetCodecFactoryimplements ProtocolCodecFactory {
@Override
public ProtocolDecodergetDecoder(IoSession session)throws Exception {
return new CharsetDecoder();
}
@Override
public ProtocolEncodergetEncoder(IoSession session)throws Exception {
return new CharsetEncoder();
}
}
实际上就是我们实现mina的编解码工厂 然后注入我们自己的解码CharsetDecoder类 编码CharsetEncoder类(因为各个公司的项目的协议不同所以)
public class CharsetDecoderimplements ProtocolDecoder {
@Override
public void decode(IoSession ioSession, IoBuffer ioBuffer, ProtocolDecoderOutput protocolDecoderOutput)throws Exception {
//拿到iobuffer的流以后然后按照大家各个协议不同的处理方式进行解析,包括一些粘包的操作也是在这里进行处理,处理完的数据我们通过protocolDecoderOutput输出到ServerMessageHandler这个类进行我们的消息集中分类处理回复等操作
}
@Override
public void finishDecode(IoSession ioSession, ProtocolDecoderOutput protocolDecoderOutput)throws Exception {
}
@Override
public void dispose(IoSession ioSession)throws Exception {
}
}
ServerMessageHandler这个类也是根据不同的人的不同业务需求有所差别 所以也是实现的mina的方法
public class ServerMessageHandlerimplements IoHandler {
@Override
public void sessionCreated(IoSession ioSession)throws Exception {
}
@Override
public void sessionOpened(IoSession ioSession)throws Exception {
}
@Override
public void sessionClosed(IoSession ioSession)throws Exception {
//这个方法在tcp通信中我们客户端正常关闭时会发出关闭通知的 在实际的业务需求当中我们会将这个在线的session存到一个map当中,当他关闭的时候进行移出就好了
}
@Override
public void sessionIdle(IoSession ioSession, IdleStatus idleStatus)throws Exception {
}
@Override
public void exceptionCaught(IoSession ioSession, Throwable throwable)throws Exception {
}
@Override
public void messageReceived(IoSession ioSession, Object o)throws Exception {
//在这个方法中我们可以处理消息 object即我们消息的泛型 取得时候只用强转成我们需要的类型就好了
}
@Override
public void messageSent(IoSession ioSession, Object o)throws Exception {
}
@Override
public void inputClosed(IoSession ioSession)throws Exception {
}
}
而当我们使用了mina框架的时候,发消息是真的很简单啊,不用考虑线程那些,拿到对应客户端的session 然后使用mIoSession.write(data);就完了.当然我们一般的
tcp通信都会有自己的封包方式,这个时候就需要我们的CharsetEncoder类,而我们的mIoSession.write(data)的数据也是输出到这个类中进行一个集中的封包处理的:
到这里我们服务端从接受数据到解码到处理数据然后发送数据到编码最后发送的完成流程就完成了,避免nio一系列的东西.另外如果你想要在外面随时能够取出来
session进行发送的话,我们只用在最开始的消息处理的时候将各个客户端的session存到一个map里面就完了,注意你的key必须唯一.