结合http://blog.csdn.net/wuliusir/article/details/51206654这篇博客来了mina在项目中的用法
用配置文件来管理
-----------------------------------------------------------------------------
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://192.168.32.98:8083/spring-beans.dtd">
<beans>
<!-- This makes it possible to specify java.net.SocketAddress values (e.g.
:80 below) as Strings. They will be converted into java.net.InetSocketAddress
objects by Spring. -->
<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="customEditors">
<map>
<entry key="java.net.SocketAddress">
<bean class="org.apache.mina.integration.beans.InetSocketAddressEditor" />
</entry>
</map>
</property>
</bean>
<!-- The IoHandler implementation -->
<bean id="mhHandler" class="com.cvicse.ksccs.fes.socketserver.SocketServerHandler">
</bean>
<bean id="executorFilter" class="org.apache.mina.filter.executor.ExecutorFilter">
<constructor-arg value="10" />
<constructor-arg value="50" />
</bean>
<bean id="codecFilter" class="org.apache.mina.filter.codec.ProtocolCodecFilter">
<constructor-arg>
<bean class="com.cvicse.ksccs.fes.socketserver.IntMsgLenghtProtocolCodecFactory" />
</constructor-arg>
</bean>
<bean id="loggingFilter" class="org.apache.mina.filter.logging.LoggingFilter" />
<bean id="filterChainBuilder"
class="org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder">
<property name="filters">
<map>
<entry key="executor" value-ref="executorFilter" />
<entry key="codecFilter" value-ref="codecFilter" />
<entry key="loggingFilter" value-ref="loggingFilter" />
</map>
</property>
</bean>
<bean id="ioAcceptor" class="org.apache.mina.transport.socket.nio.NioSocketAcceptor"
init-method="bind" destroy-method="unbind">
<property name="defaultLocalAddress" value="9988" />
<property name="handler" ref="mhHandler" />
<property name="reuseAddress" value="true" />
<property name="filterChainBuilder" ref="filterChainBuilder" />
</bean>
</beans>
---------------------------------------------------------------------------------------------------------------------
Server 端的 Main 函数:
IoAcceptor acceptor = new NioSocketAcceptor(); // 建立监控器
//acceptor.getSessionConfig().setReadBufferSize(2048);
//acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE , 10);
acceptor.getFilterChain().addLast("codec ",
New ProtocolCodecFilter(new TextLineCodecFactory(Charset.forName("UTF-8"),
LineDelimiter.WINDOWS.getValue(), LineDelimiter.WINDOWS.getValue())));// 加载解 / 编码工厂
acceptor.setHandler(new StandBaowenHandler ()); // 设置处理类,其主要内容见下。
acceptor.bind(new InetSocketAddress(9998));// 绑定的监听端口,可多次绑定,也可同时绑定多个。
StandBaowenHandler 的关键代码
public void messageReceived(IoSession session, Object message) throws Exception { session.getService().getManagedSessions();
String baowenSrc = message.toString();// 原始报文
System.out.println (baowenSrc );
}
(1) IoService :这个接口在一个线程上负责套接字的建立,拥有自己的 Selector ,监听是否有连接被建立。
(2) IoProcessor :这个接口在另一个线程上负责检查是否有数据在通道上读写,也就是说它也拥有自己的 Selector ,这是与我们使用 JAVA NIO 编码时的一个不同之处,
通常在 JAVA NIO 编码中,我们都是使用一个 Selector ,也就是不区分 IoService 与 IoProcessor 两个功能接口。另外,IoProcessor 也是 MINA 框架的核心组件之一 . 在 MINA 框架启动时,会用一个线程池来专门生成线程,来负责调用注册在IoService 上的过滤器,并在过滤器链之后调用 IoHandler 。在默认情况 IoProcessor 会用 N+1 个线程来轮流询问监视的端口是否有数据传送,其中 n 为 cpu 的内核个数。按一般的多线程设计概念来说, IoProcessor 的线程数是越多越好,但实际上并非如此,因为大家都知道, IO 的操作是非常占用资源的,所以项目中的 IoProcessor 的线程数应该根据实际需要来定,而这个数字可以在生成 IoAcceptor 对象时进行设定。 Eg IoAcceptor acceptor = new NioSocketAcceptor( N );
(3.) IoFilter :这个接口定义一组拦截器,这些拦截器可以包括日志输出、黑名单过滤 ( 参见之前代码示例的注释部份 ) ,甚至是在过滤器链中利用 AOP 写上权限控制(笔者负责的部分没有涉及到这权限部分,但根据笔者对框架的理解要实现这一点应该问题不大,有需要的可以自行试验)。数据的编码( write 方向)与解码( read 方向)等功能,其中数据的 encode 与 decode是最为重要的、也是您在使用 Mina 时最主要关注的地方(笔者曾经为了 decode 的解码编写,重写了不下十几种实现方式才找到准确无误适合项目的解码方法)。
(4.) IoHandler :这个接口负责编写业务逻辑,也就是接收、发送数据的地方。只本文的代码实例中,可以看到真正的业务代码只有一句 :System.out.println(str); 真实项目中当然不可能如此简单,但如果大家把业务处理写好,并写好业务接口,真正要用时,呆需要在此处替换即可,再次见证了 MINA 分层的彻底。
对应的代码:
------------------------------------------------------handler----------------------------------------------------------------------
package com.cvicse.ksccs.fes.socketserver;
import java.util.HashMap;
import java.util.Map;
import org.apache.log4j.Logger;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.transport.socket.SocketSessionConfig;
import com.cvicse.eps.common.Constant;
import com.cvicse.eps.common.ResponseType;
import com.cvicse.ksccs.fes.business.ReqMsgHandlerItf;
import com.cvicse.ksccs.fes.business.impl.PMSReqMsgHandler;
import com.cvicse.ksccs.fes.config.FESDealConfig;
import com.cvicse.ksccs.fes.config.FESSocketConfig;
import com.cvicse.ksccs.fes.jms.SocketClients;
import com.cvicse.ksccs.fes.localresource.LocalResource;
import com.cvicse.ksccs.fes.message.FESMessage;
import com.cvicse.ksccs.fes.message.MessageDeal;
import com.cvicse.ksccs.fes.message.MessageHeader;
import com.cvicse.ksccs.fes.message.ParserDealFactory;
import com.cvicse.ksccs.fes.util.FESConstant;
import com.cvicse.ksccs.fes.util.MsgMAC;
/**
*
* @description mina-socket处理类
* @author fei_yfan
* @version 1.0
* @create_date 2013-10-17
* @copyright (c) CVIC SE
*/
public class SocketServerHandler extends IoHandlerAdapter {
public static Logger logger = Logger.getLogger(SocketServerHandler.class);
/**
* 当会话创建是调用该方法
*/
public void sessionCreated(IoSession session) throws Exception {
logger.info("服务端与客户端" + session.getRemoteAddress() + "创建连接...");
SocketSessionConfig cfg = (SocketSessionConfig) session.getConfig();
cfg.setKeepAlive(true);
// cfg.setSoLinger(0); // 这个是根本解决问题的
}
/**
* 当网络连接被打开时此方法被调用,这里可以对session设置一些参数或者添加一些IoFilter的实现,也可以对客户端做一些认证之类的工作
*/
public void sessionOpened(IoSession session) throws Exception {
logger.info("服务端与客户端" + session.getRemoteAddress() + "连接打开...");
session.getConfig().setIdleTime(IdleStatus.BOTH_IDLE, 10);
}
/**
* 接收消息函数
*/
public synchronized void messageReceived(IoSession session, Object message) {
String responseMsg = "";
MessageHeader reqMsgHeader = new MessageHeader();
Map<String, String> reqMsgBody = new HashMap<String, String>();
IoBuffer messageIo = (IoBuffer) message;
IoBuffer buf = null;
// 缴费平台服务IP
String epsIP= FESSocketConfig.getFESConfig().getLtEpsIp();
// 清算服务IP
String bepsIP= FESSocketConfig.getFESConfig().getLtBepsIp();
try {
byte[] bytes = messageIo.array();
String tempMsg = "";
tempMsg = new String(bytes);
logger.info("\n监听到的请求报文:" + tempMsg);
// 区分清算报文、水报文
String IP=session.getRemoteAddress().toString();
IP=IP.substring(IP.indexOf("/")+1,IP.indexOf(":"));
// 区分清算报文、水报文
if(IP.contains(bepsIP)){
// 得到交易报文适配类集合
ParserDealFactory msgDeal2Parser = FESDealConfig.getFESConfig()
.getMsgdeal2Parser();
// 获取交易报文适配类对象
MessageDeal messageDeal = (MessageDeal) msgDeal2Parser
.getdeal2ParserMap().get(Constant.BEPS22PMS);
FESMessage messageValueObject = messageDeal.msgDeal(tempMsg,
Constant.BEPS22PMS);
reqMsgHeader = messageValueObject.getReqMsgHeader();
reqMsgBody = messageValueObject.getReqMsgBody();
// 校验MAC码
if (MsgMAC.checkMAC(tempMsg, 0)) {
//
ReqMsgHandlerItf itf = new PMSReqMsgHandler();
responseMsg = itf.paraseReqMsg(reqMsgHeader, reqMsgBody);
logger.info("\n业务处理后的响应内容:" + responseMsg);
} else {
// MAC校验没有通过,则响应码为F005
responseMsg = ResponseType.NOT_PASS_MAC_CHECK;
// 日志跟踪
logger.info("\n请求方的MAC校验没有通过!");
}
byte[] responseMsgByte = ResSocketMsgHandlerImpl.createResMsg(
tempMsg, responseMsg, 0);
int length = responseMsgByte.length;
buf = IoBuffer.allocate(length);
buf.put(responseMsgByte);
buf.flip();
}else if (IP.contains(epsIP)){
// 获取服务IP
String serviceIp = FESSocketConfig.getFESConfig().getLtWaterIp();
// 获取服务端口
int port = FESSocketConfig.getFESConfig().getLtWaterPort();
SocketClients sc = new SocketClients(serviceIp, port);
byte[] responseMsgByte = sc.relayMsg(bytes, FESConstant.SYDWID_WATER);
int length = responseMsgByte.length;
buf = IoBuffer.allocate(length);
buf.put(responseMsgByte);
buf.flip();
}
} catch (Exception e) {
logger.error(LocalResource.getInfor("BUSINESS_FAIL_EXCEPTION"), e);
// 数据操作异常
// responseMsg = ResponseType.DATABASE_OPERATE_ERROR;
}
session.write(buf);
}
/**
* 当消息传送到客户端后触发
*/
public void messageSent(IoSession session, Object message) throws Exception {
logger.info("服务端发送到客户端" + session.getRemoteAddress() + "信息成功...");
/*
* //如果需要短连接,就将下面方法放开
*/
session.close();
}
/**
* 当网络连接关闭时候,调用此方法
*/
public void sessionClosed(IoSession session) throws Exception {
// session.getRemoteAddress()=null
logger.info("与客户端" + session.getRemoteAddress() + "断开连接!");
}
/**
* // 当网络通道空闲时此方法被调用,在这里可以判断是读空闲、写空闲还是两个都空闲,以便做出正确的处理 //
* 一半的网络通讯程序都要与服务器端保持长连接,所以这里可以发一下网络测试数据以保持与服务器端的连接
*/
public void sessionIdle(IoSession session, IdleStatus status)
throws Exception {
// 当网络通道空闲时此方法被调用,在这里可以判断是读空闲、写空闲还是两个都空闲,以便做出正确的处理
// 一半的网络通讯程序都要与服务器端保持长连接,所以这里可以发一下网络测试数据以保持与服务器端的连接
logger.info("服务端进入空闲状态...");
}
/**
* 当出现异常时,被调用该方法
*/
public void exceptionCaught(IoSession session, Throwable cause)
throws Exception {
logger.error("服务端发送异常...", cause);
}
}
-------------------------------------------------------------------------------------------
public class SocketServer {
private String configFilePath;
private ClassPathXmlApplicationContext context;
public SocketServer() {
this.configFilePath = "SocketServer.xml";
}
public SocketServer(String configFilePath) {
this.configFilePath = configFilePath;
}
public static void main(String[] args) throws Exception {
new SocketServer().start();
}
public void start() {
context = new ClassPathXmlApplicationContext(configFilePath);
}
public void stop() {
context.destroy();
}
}
----------------------------------测试类--------------------------------------------------
【public class SocketServerHandlerTest {
// 日志
public static Logger logger = Logger.getLogger(SocketServerHandlerTest.class);
/**
* @param args
*/
public static void main(String[] args) {
new SocketServer("SocketServer.xml").start();
}
】
------------------------------------拦截器-----------------------------------------------------
package com.cvicse.ksccs.fes.socketserver;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.CumulativeProtocolDecoder;
import org.apache.mina.filter.codec.ProtocolDecoderOutput;
public class IntMsgLenghtProtocolDecoder extends CumulativeProtocolDecoder {
@Override
protected boolean doDecode(IoSession session, IoBuffer in,
ProtocolDecoderOutput out) throws Exception {
byte[] bytes = new byte[in.limit()];
in.get(bytes);
IoBuffer buf = IoBuffer.allocate(in.limit());
buf.put(bytes);
buf.flip();
out.write(buf);
return true;
}
}
package com.cvicse.ksccs.fes.socketserver;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolCodecFactory;
import org.apache.mina.filter.codec.ProtocolDecoder;
import org.apache.mina.filter.codec.ProtocolEncoder;
import org.apache.mina.filter.codec.ProtocolEncoderAdapter;
import org.apache.mina.filter.codec.ProtocolEncoderOutput;
/**
* @author han_feng
*
*/
public class IntMsgLenghtProtocolCodecFactory implements ProtocolCodecFactory {
private final MessageEncoder encoder;
private final IntMsgLenghtProtocolDecoder decoder;
public IntMsgLenghtProtocolCodecFactory() {
encoder = new MessageEncoder();
decoder = new IntMsgLenghtProtocolDecoder();
}
public ProtocolDecoder getDecoder(IoSession session) throws Exception {
return decoder;
}
public ProtocolEncoder getEncoder(IoSession session) throws Exception {
return encoder;
}
/**
* 译码器,不做任何事情
*/
private static class MessageEncoder extends ProtocolEncoderAdapter {
public void encode(IoSession session, Object message,
ProtocolEncoderOutput out) throws Exception {
}
}
}