浅谈MINA的使用
来源:互联网 发布:理性 知乎 编辑:程序博客网 时间:2024/05/29 07:10
http://blog.csdn.net/yuan16423276
最近做了一个POS终端通信的小项目,主要是给POS终端提供TCP接口。之前的工作中没有从事相关的开发,也没涉及到网络通信的相关框架,在网上找了一些相关资料,最终选用了apache下的mina框架。
mina框架是一个网络通信框架,也就是它是基于TCP/IP、UDP/IP的协议栈的通信框架。mina对Java的socket进行了封装,我们在使用mina时不用把过多的精力放在网络通信的开发上,mina给我们提供了事件驱动、异步它的异步默认使用的是java noi作为异步支持。同时mina对通信的客户端和服务端都进行了封装,我们可以轻松的使用mina进行服务端可客户端的开发。
(1.) IoService:这个接口在一个线程上负责套接字的建立,拥有自己的Selector,监听是否有连接被建立。
(2.) IoProcessor:这个接口在另一个线程上,负责检查是否有数据在通道上读写,也就是说它也拥有自己的Selector,这是与我们使用JAVA NIO 编码时的一个不同之处,通常在JAVA NIO 编码中,我们都是使用一个Selector,也就是不区分IoService与IoProcessor 两个功能接口。另外,IoProcessor 负责调用注册在IoService 上的过滤器,并在过滤器链之后调用IoHandler。
(3.) IoFilter:这个接口定义一组拦截器,这些拦截器可以包括日志输出、黑名单过滤、数据的编码(write 方向)与解码(read 方向)等功能,其中数据的encode 与decode是最为重要的、也是你在使用Mina 时最主要关注的地方。
(4.) IoHandler:这个接口负责编写业务逻辑,也就是接收、发送数据的地方。
废话不多说,以下是我自己编写的服务端程序,贴出来供大家参考学习:
- import java.net.InetSocketAddress;
- import org.apache.log4j.Logger;
- import org.apache.mina.core.session.IdleStatus;
- import org.apache.mina.filter.codec.ProtocolCodecFilter;
- import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
- import com.chinaums.umscard.socket.codec.MsgCodecFactory;
- import com.chinaums.umscard.util.BaseConfig;
- public class MinaServer {
- private static final Logger log = Logger.getLogger(MinaServer.class);
- public static void main(String[] args) {
- // 创建一个非阻塞的server端的Socket
- NioSocketAcceptor acceptor = new NioSocketAcceptor();
- try {
- // 设置过滤器(使用自己封装的编解码器)
- acceptor.getFilterChain().addLast("codec",new ProtocolCodecFilter(new MsgCodecFactory("UTF-8")));
- // 设置读取数据的缓冲区大小为1M
- acceptor.getSessionConfig().setReadBufferSize(1024*1024);
- // 读写通道10秒内无操作进入空闲状态
- acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 10);
- // 绑定逻辑处理器
- acceptor.setHandler(new MinaServerHandler());
- // 绑定端口
- acceptor.bind(new InetSocketAddress(BaseConfig.PORT));
- log.info("服务端启动。。。。。端口号为:"+BaseConfig.PORT);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
- 请注意,过滤器可以使用mina提供的过滤器,也可以自己根据需要编写过滤器。这里我使用的自己编写的过滤器
- 过滤器代码如下
- 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;
- public class MsgCodecFactory implements ProtocolCodecFactory {
- //这里注册自己编写的解码工具
- private final MsgResponseEncoder encoder; // 编码
- private final MsgRequestDecoder decoder; // 解码
- public MsgCodecFactory(String charset) {
- encoder = new MsgResponseEncoder(charset);
- decoder = new MsgRequestDecoder(charset);
- }
- public ProtocolEncoder getEncoder(IoSession session) {
- return encoder;
- }
- public ProtocolDecoder getDecoder(IoSession session) {
- return decoder;
- }
- 解码代码如下
- import org.apache.log4j.Logger;
- 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;
- import com.chinaums.umscard.util.StringUtils;
- public class MsgRequestDecoder extends CumulativeProtocolDecoder {
- private static final Logger LOGGER = Logger.getLogger(MsgRequestDecoder.class);
- private final String charset;
- public MsgRequestDecoder(String charset) {
- this.charset = charset;
- }
- /**
- *解码器,对传入的iobuffer 进行解码工作,注意顺序是先进先出原则。
- */
- @Override
- protected boolean doDecode(IoSession session, IoBuffer in,
- ProtocolDecoderOutput out) throws Exception {
- // TODO Auto-generated method stub
- if (in.remaining() > 2) {
- in.mark();// 标记当前位置,以便reset
- byte[] lenBytes = new byte[3];
- in.get(lenBytes);
- int length = Integer.parseInt(StringUtils.hexStr2Str(StringUtils.bytes2HexString(lenBytes)));
- // int length = StringUtils.bytesToInt(lenBytes);
- if (length > in.remaining()) {// 如果消息内容不够,则重置,相当于不读取size
- System.out.println("package notenough left=" + in.remaining()
- + " length=" + length);
- in.reset();
- return false;// 接收新数据,以拼凑成完整数据
- } else {
- System.out.println("package =" + in.toString());
- byte[] bbIn = new byte[length];
- in.get(bbIn, 0, length);
- byte[] btotal = new byte[length];
- System.arraycopy(bbIn, 0, btotal, 0, bbIn.length);
- byte[] pwd = new byte[8];
- System.arraycopy(btotal, btotal.length-8, pwd, 0, 8);
- System.out.println(StringUtils.bytes2HexString(pwd));
- String result = StringUtils.bytes2HexString(btotal);
- out.write(result);
- if (in.remaining() > 0) {// 如果读取内容后还粘了包,就让父类再给一次,进行下一次解析
- // System.out.println("package left="+in.remaining()+" data="+in.toString());
- }
- return true;// 这里有两种情况1:没数据了,那么就结束当前调用,有数据就再次调用
- }
- }
- return false;// 处理成功,让父类进行接收下个包
- }
- }
- import java.nio.charset.Charset;
- import org.apache.mina.core.buffer.IoBuffer;
- import org.apache.mina.core.session.IoSession;
- import org.apache.mina.filter.codec.ProtocolEncoderAdapter;
- import org.apache.mina.filter.codec.ProtocolEncoderOutput;
- public class MsgResponseEncoder extends ProtocolEncoderAdapter {
- private final String charset;
- public MsgResponseEncoder(String charset) {
- this.charset = charset;
- }
- public void encode(IoSession session, Object message,
- ProtocolEncoderOutput out) throws Exception {
- IoBuffer buf = IoBuffer.allocate(100).setAutoExpand(true);
- String strOut = message.toString();
- // buf.putInt(strOut.getBytes(Charset.forName("utf-8")).length);
- buf.putString(strOut,Charset.forName("GBK").newEncoder());
- buf.flip();
- out.write(buf);
- }
- }
- 以下是业务处理类
- import java.util.List;
- import org.apache.log4j.Logger;
- import org.apache.mina.core.service.IoHandlerAdapter;
- import org.apache.mina.core.session.IdleStatus;
- import org.apache.mina.core.session.IoSession;
- import com.chinaums.umscard.entity.AccountInfo;
- import com.chinaums.umscard.entity.BasCardPos;
- import com.chinaums.umscard.entity.CardMeracc;
- import com.chinaums.umscard.entity.ConsumeParam;
- import com.chinaums.umscard.entity.DataAccReturn;
- import com.chinaums.umscard.entity.DataPosFlow;
- import com.chinaums.umscard.entity.PayTranPay;
- import com.chinaums.umscard.entity.RejectGoodsParam;
- import com.chinaums.umscard.service.AccountInfoService;
- import com.chinaums.umscard.service.CardMeraccService;
- import com.chinaums.umscard.service.ConsumeService;
- import com.chinaums.umscard.service.DataAccReturnService;
- import com.chinaums.umscard.service.DataFlowService;
- import com.chinaums.umscard.service.PosCheckService;
- import com.chinaums.umscard.service.RejectGoodsService;
- import com.chinaums.umscard.service.ReverseService;
- import com.chinaums.umscard.service.impl.AccountInfoServiceImpl;
- import com.chinaums.umscard.service.impl.CardMeraccServiceImpl;
- import com.chinaums.umscard.service.impl.ConsumeServiceImpl;
- import com.chinaums.umscard.service.impl.DataAccReturnServiceImpl;
- import com.chinaums.umscard.service.impl.DataFlowServiceImpl;
- import com.chinaums.umscard.service.impl.PosCheckServiceImpl;
- import com.chinaums.umscard.service.impl.RejectGoodsServiceImpl;
- import com.chinaums.umscard.service.impl.ReverseServiceImpl;
- import com.chinaums.umscard.util.MySecurityUtil;
- import com.chinaums.umscard.util.StringUtils;
- import com.chinaums.umscard.util.XorUtil;
- public class MinaServerHandler extends IoHandlerAdapter {
- public static final Logger log = Logger.getLogger(MinaServerHandler.class);
- @Override
- public void sessionCreated(IoSession session) throws Exception {
- log.info("服务端与客户端创建连接...");
- }
- @Override
- public void sessionOpened(IoSession session) throws Exception {
- log.info("服务端与客户端打开连接");
- }
- @Override
- public void sessionClosed(IoSession session) throws Exception {
- log.info("服务端与客户端关闭连接");
- }
- //这个方法用于接收监听接收到的报文数据,以进行相关的业务处理
- @Override
- public void messageReceived(IoSession session, Object message) throws Exception{
- String m = message.toString();
- String bcd = m.substring(m.length()-16);
- // System.out.println(bcd);
- byte[] bt = message.toString().getBytes();
- byte[] keypwdbt = new byte[8];
- System.arraycopy(bt, bt.length-8, keypwdbt, 0, 8);
- String result = MySecurityUtil.bcd2Str(keypwdbt);
- String msg = StringUtils.hexStr2Str(message.toString());
- // PosCheckService posService = new PosCheckServiceImpl();
- PosCheckService posCheckService = new PosCheckServiceImpl();
- DataFlowService dataFlowService = new DataFlowServiceImpl();
- MySecurityUtil ms = new MySecurityUtil();
- // PosCheckService posService = new PosCheckServiceImpl();
- if(msg != null){
- String msgArr = msg.replace("|", ",");
- String[] posArr = msgArr.split(",");
- if(msg.toString().startsWith("0001")){
- String checkmsg = "";//用于接收签到结果
- String posno = posArr[1];
- String key = posArr[2];
- String keypwd = posArr[3];//异或加密后的验证码
- StringBuffer sb = new StringBuffer();
- sb.append(posArr[0]);
- sb.append("|");
- //以下将报文进行异或加密处理(不取最后一个元素)
- for(int i=1;i<posArr.length-1;i++){
- sb.append(posArr[i]+",");
- }
- System.out.println(sb);
- //异或运算
- byte[] b = XorUtil.xorChar(sb.toString().toCharArray());
- //加密
- byte[] key1 = MySecurityUtil.hexStr2Str(key.substring(0, key.length()/2)).getBytes();
- byte[] key2 = MySecurityUtil.hexStr2Str(key.substring(key.length()/2)).getBytes();
- byte[] p = ms.TripleDesEncrypt(b, key1, key2);
- //转成字符串
- String s = MySecurityUtil.bcd2Str(p);
- BasCardPos basCardPos = posCheckService.checkPos(posno);
- if(basCardPos != null && basCardPos.getIkey().equals(posArr[2])){
- checkmsg = "00";//签到成功
- }else if(basCardPos != null && basCardPos.getIkey() != posArr[2]){
- checkmsg = "99";//密钥验证失败
- }else{
- checkmsg = "01";//签到失败
- }
- //插入日志
- DataPosFlow dataPosFlow = new DataPosFlow();
- dataPosFlow.setPosno(posno);
- dataPosFlow.setVreturn(checkmsg);
- dataFlowService.PosCheckDataFlow(dataPosFlow);
- session.write(checkmsg+"#"+s);
- log.info(checkmsg);
- }else if(msg.toString().startsWith("0002")){
- AccountInfoService accService = new AccountInfoServiceImpl();
- String selectmsg = "";//用于接收查询账户返回的状态码
- //取磁道内容
- String cardnoecp = posArr[1];
- //取终端号
- String posno = posArr[2];
- //获取密钥
- String key = posArr[3];
- //获取密码
- String pwd = posArr[4];
- //第一步检查终端的合法性
- BasCardPos bcp = posCheckService.checkPos(posno);
- StringBuffer sb = new StringBuffer();
- if(bcp != null && bcp.getIkey().equals(key)){
- List<AccountInfo> accList = accService.checkAccount(cardnoecp);
- DataPosFlow dataPosFlow = null;
- if(accList != null && accList.size() != 0){
- selectmsg = "00";//查询成功
- sb.append(selectmsg+"#");
- for(AccountInfo account : accList){
- // String hexAccountName = new String(account.getAccname().getBytes("UTF-8"), "GB18030");
- sb.append(account.getCardid()+","+account.getCardno()+","
- +account.getAccid()+","+account.getAccname()+","+account.getBalance()+"|");
- dataPosFlow = new DataPosFlow();
- dataPosFlow.setCardid(account.getCardid());
- dataPosFlow.setAccid(account.getAccid());
- dataPosFlow.setPosno(posno);
- dataPosFlow.setVreturn(selectmsg);
- dataFlowService.AccountInfoDataFlow(dataPosFlow, account);
- }
- session.write(sb);
- }else{
- selectmsg = "98";
- session.write(selectmsg+"#");
- }
- }else if(bcp != null && !key.equals(bcp.getIkey())){
- selectmsg = "99";
- session.write(selectmsg+"#");
- }
- log.info(selectmsg);
- }else if(msg.toString().startsWith("0003")){
- ConsumeService consumeService = new ConsumeServiceImpl();
- String consumemsg = "";
- //获取cardid
- String cardid = posArr[1];
- //获取accid
- String accid = posArr[2];
- String trantype = posArr[3];
- String amt = posArr[4];
- //获取终端号
- String posno = posArr[5];
- //获取密钥
- String key = posArr[6];
- String pwd = posArr[7];
- String possno = posArr[8];
- // String field1 = posArr[8];
- ConsumeParam param = new ConsumeParam();
- param.setCardid(Float.parseFloat(cardid));
- param.setAccid(3f);
- param.setAmt(Float.parseFloat(amt)/100);
- param.setPosno(posno);
- param.setPossno(possno);
- param.setTrainType(Float.parseFloat(trantype));
- BasCardPos bcp = posCheckService.checkPos(posno);
- //终端验证成功,验证卡是否可以在终端上使用
- if(bcp != null && key.equals(bcp.getIkey())){
- int count = consumeService.poscount(Integer.parseInt(cardid), Integer.parseInt(accid));
- //count不为0说明卡片可以在终端上使用
- if(count != 0){
- consumemsg = consumeService.consume(param);
- }else if(key != bcp.getIkey()){
- consumemsg = "99";//密钥验证失败
- }else if(count == 0){
- consumemsg = "98";//不存在卡
- }else{
- consumemsg = "97";//密码错误
- }
- }
- session.write(consumemsg+"#");
- log.info(consumemsg);
- }else if(msg.toString().startsWith("0004")){
- String rejectmsg = "";
- String cardid = posArr[1];
- String rejectTranType = posArr[2];
- String rejectPosno = posArr[3];
- String rejectkey = posArr[4];
- String rejectpwd = posArr[5];
- String rejectTranId = posArr[6];
- RejectGoodsParam param = new RejectGoodsParam();
- param.setCardid(Integer.parseInt(cardid));
- param.setKey(rejectkey);
- param.setPosno(rejectPosno);
- param.setPwd(rejectpwd);
- param.setTranid(rejectTranId);
- param.setTranType(Integer.parseInt(rejectTranType));//退货
- BasCardPos bcp = posCheckService.checkPos(rejectPosno);
- RejectGoodsService rgService = new RejectGoodsServiceImpl();
- DataAccReturnService dataAccReturnService = new DataAccReturnServiceImpl();
- if(bcp != null && rejectkey.equals(bcp.getIkey())){
- //根据传入的信息查询用户的卡信息和原单号,以便验证交易信息是否属实
- //验证成功,查询账户信息,返回账户信息
- rejectmsg = rgService.rejectGoods(param);
- //交易信息存在返回00向退货申请表中写入退货申请
- if (rejectmsg.equals("00")) {
- //查询交易记录
- PayTranPay pay = rgService.getPayTranPay(param);
- //验证成功将退货请求写入退货请求表
- DataAccReturn dataAccReturn = new DataAccReturn();
- dataAccReturn.setCashierno(rejectPosno);
- dataAccReturn.setTranid(rejectTranId);
- dataAccReturn.setPosno(rejectPosno);
- dataAccReturn.setCardid(Integer.parseInt(cardid));
- dataAccReturn.setAccid(Integer.parseInt(pay.getPaysubtype()));
- dataAccReturn.setAmt(pay.getAmt());
- dataAccReturn.setPosno(rejectPosno);
- dataAccReturnService.addDataAccReturn(dataAccReturn);
- }
- }else if(bcp != null && !rejectkey.equals(bcp.getIkey())){
- rejectmsg = "99";
- }else{
- rejectmsg = "97";
- }
- CardMeraccService cardMeraccService = new CardMeraccServiceImpl();
- CardMeracc cardm = cardMeraccService.getCardMeraccByCardId(Integer.parseInt(cardid));
- DataPosFlow dataPosFlow = new DataPosFlow();
- dataPosFlow.setCardid(Integer.parseInt(cardid));
- dataPosFlow.setPosno(rejectPosno);
- dataPosFlow.setVreturn(rejectmsg);
- //写入日志
- dataFlowService.RejectGoodsDataPosFlow(dataPosFlow, cardm);
- session.write(rejectmsg+"#");
- }else if(msg.toString().startsWith("0005")){
- String reveremsg = "";
- //pos终端号
- String posno = posArr[1];
- //密钥
- String key = posArr[2];
- //批次号(POS终端生成)
- String posSno = posArr[3];
- //预留字段
- // String field1 = posArr[4];
- ReverseService reverserService = new ReverseServiceImpl();
- reveremsg = reverserService.reverse(posSno, posno);
- session.write(reveremsg+"#");
- }
- }
- log.info("服务端收到的数据为:"+message);
- }
- @Override
- public void messageSent(IoSession session, Object message) throws Exception {
- log.info("服务端发送消息成功!");
- }
- @Override
- public void sessionIdle(IoSession session, IdleStatus status) throws Exception {
- log.info("服务端进入空闲状态...");
- }
- @Override
- public void exceptionCaught(IoSession session, Throwable cause) throws Exception {
- log.error("服务端发送异常...", cause);
- }
- }
- import java.net.InetAddress;
- import java.net.InetSocketAddress;
- import java.net.UnknownHostException;
- import java.nio.charset.Charset;
- import org.apache.log4j.Logger;
- import org.apache.mina.core.future.ConnectFuture;
- import org.apache.mina.core.service.IoConnector;
- import org.apache.mina.core.session.IoSession;
- import org.apache.mina.filter.codec.ProtocolCodecFilter;
- import org.apache.mina.filter.codec.textline.LineDelimiter;
- import org.apache.mina.filter.codec.textline.TextLineCodecFactory;
- import org.apache.mina.transport.socket.nio.NioSocketConnector;
- public class MinaClient {
- private static final Logger logger = Logger.getLogger(MinaClient.class);
- // private static String ip = address.get
- public static void main(String[] args) throws UnknownHostException {
- InetAddress address = InetAddress.getLocalHost();
- String ip = address.getHostAddress().toString();
- // 创建一个非阻塞的客户端程序
- IoConnector connector = new NioSocketConnector();
- // 设置链接超时时间
- connector.setConnectTimeout(30000);
- // 添加过滤器
- connector.getFilterChain().addLast(
- "codec",
- new ProtocolCodecFilter(new TextLineCodecFactory(Charset
- .forName("UTF-8"), LineDelimiter.WINDOWS.getValue(),
- LineDelimiter.WINDOWS.getValue())));
- // 添加业务逻辑处理器类
- connector.setHandler(new MinaClientHandler());
- IoSession session = null;
- try {
- ConnectFuture future = connector.connect(new InetSocketAddress(
- ip, 2000));// 创建连接
- future.awaitUninterruptibly();// 等待连接创建完成
- session = future.getSession();// 获得session
- // Scanner s = new Scanner(System.in);
- // String msg = s.next();
- session.write("0001|10003,44444444444444444444444444444444,null");// 发送消息
- session.write("quit");//发送后与服务端断开连接
- } catch (Exception e) {
- logger.error("客户端链接异常...", e);
- }
- // session.getCloseFuture().awaitUninterruptibly();//等待连接断开
- connector.dispose();
- }
- }
- import org.apache.log4j.Logger;
- import org.apache.mina.core.service.IoHandlerAdapter;
- import org.apache.mina.core.session.IoSession;
- public class MinaClientHandler extends IoHandlerAdapter {
- private static Logger logger = Logger.getLogger(MinaClientHandler.class);
- @Override
- public void messageReceived(IoSession session, Object message)
- throws Exception {
- String msg = message.toString();
- logger.info("客户端接收到的信息为:" + msg);
- }
- @Override
- public void exceptionCaught(IoSession session, Throwable cause)
- throws Exception {
- logger.error("客户端发生异常...", cause);
- }
- }
- 浅谈MINA的使用
- 浅谈MINA的使用
- mina的基础使用
- MINA的使用
- MINA的使用
- Mina框架的使用
- Mina的使用
- Mina框架的使用
- Mina的使用简介
- java mina的使用
- 浅谈Java的Mina框架传递对象
- 浅谈Java的Mina框架传递对象
- 浅谈Java的Mina框架传递对象
- Mina实时框架的使用
- 首次使用Mina(使用Mina建立简单的服务器)
- [MINA]android2.2中使用mina注意的问题
- Mina使用
- 使用mina解析http协议的使用
- 递归、迭代与动态规划实现菲波那切数列
- logback 日志详述
- eclipse mars(4.5.2)中安装spring tool suite
- 详解Objective-C runtime
- java的public、default、protected、public四个方法有什么区别
- 浅谈MINA的使用
- 学习IOS的第四天
- test
- hdu 3555 Bomb (数位dp)
- EventBus 使用心得及技巧
- ROS navigation stack
- android应用性能优化之帧率
- 定义向量类
- 2019 数列有序!