apache mina 自定义编码解码

本文介绍如何在Mina中自定义数据传输的编码和解码方式,通过实现ProtocolCodecFactory、ProtocolDecoder和ProtocolEncoder接口,定义传输数据格式并进行编码解码。包括编码类MyEncoder、解码类MyDecoder及工厂类MyCodeFactory的实现,以及在server和client端的配置使用。

mina允许自定义数据传输的编码和解码方式 

需要 
实现ProtocolCodecFactory接口的工厂类 
实现ProtocolDecoder接口的解码类 
实现ProtocolEncoder接口的编码类 

本例以client和server端都是java实现 

首先定义传输的数据格式: 
编码和解码都是针对数据字节。 
数据格式:A+B+C+D 
A:固定长度 6个字节,用来简单表示时间戳, 
  月日年,时分秒每个一字节,年取后两位 
B:内容(C+D)的length,固定长度,4个字节 
C:请求指令:固定长度,4个字节 
D:传递内容:不固定,json格式 

这样针对上面的数据结构定义一个bean 
 

Java代码 

 收藏代码

  1. public class MyMessage implements Serializable {  
  2.       
  3.     /****/  
  4.     private static final long serialVersionUID = 5570201892267872279L;  
  5.     private Date date;//时间  
  6.     private int command;//指令  
  7.     private byte[] contents;//内容  
  8.     public int getCommand() {  
  9.         return command;  
  10.     }  
  11.     public void setCommand(int command) {  
  12.         this.command = command;  
  13.     }  
  14.     public byte[] getContents() {  
  15.         return contents;  
  16.     }  
  17.     public void setContents(byte[] contents) {  
  18.         this.contents = contents;  
  19.     }  
  20.       
  21.     public int length(){  
  22.         return contents.length;  
  23.     }  
  24.     public Date getDate() {  
  25.         return date;  
  26.     }  
  27.     public void setDate(Date date) {  
  28.         this.date = date;  
  29.     }  
  30. }  



编码类,继承org.apache.mina.filter.codec.CumulativeProtocolDecoder 
重新encode方法即可 
 

Java代码 

 收藏代码

  1. public class MyEncoder implements ProtocolEncoder {  
  2.     @Override  
  3.     public void encode(IoSession session, Object message,  
  4.             ProtocolEncoderOutput out) throws Exception {  
  5.         MyMessage msg = (MyMessage) message;  
  6.         IoBuffer buffer = IoBuffer.allocate(1024);  
  7.         buffer.setAutoExpand(true);  
  8.         //编码数据结构的A,时间戳  
  9.         buffer.put(getTimeTag(msg.getDate()));  
  10.         //数据结构的B  
  11.         buffer.putInt(msg.length()+4);  
  12.         //数据结构的C  
  13.         buffer.putInt(msg.getCommand());  
  14.         //数据结构的D  
  15.         buffer.put(msg.getContents());  
  16.         buffer.flip();  
  17.           
  18.         out.write(buffer);  
  19.     }  
  20.   
  21.     @Override  
  22.     public void dispose(IoSession session) throws Exception {  
  23.           
  24.     }  
  25.   
  26.     public static byte[] getTimeTag(Date date){  
  27.         if(date == null){  
  28.             date = new Date();  
  29.         }  
  30.         Calendar c = Calendar.getInstance();  
  31.         c.get(Calendar.YEAR);  
  32.         String dateStr = sdf.format(date);  
  33.         String[] dates = dateStr.split("-");  
  34.         byte[] bt = new byte[dates.length];  
  35.         for(int a=0;a<dates.length;a++){  
  36.             bt[a] = Byte.parseByte(dates[a]);  
  37.         }  
  38.         return bt;  
  39.     }  
  40. }  


解码类,继承自org.apache.mina.filter.codec.CumulativeProtocolDecoder 
重新decode方法 
 

Java代码 

 收藏代码

  1. public class MyDecoder extends CumulativeProtocolDecoder {  
  2.   
  3.     @Override  
  4.     protected boolean doDecode(IoSession session, IoBuffer in,  
  5.             ProtocolDecoderOutput out) throws Exception {  
  6.             //读取数据结构A  
  7.             byte[] dateTag = new byte[6];  
  8.             in.get(dateTag);  
  9.             //读取数据结构B  
  10.             int length =in.getInt();  
  11.             //读取数据结构C  
  12.             int command = in.getInt();  
  13.             //读取数据结构D  
  14.             byte[] bytes = new byte[length-4];  
  15.             in.get(bytes);  
  16.             //提取出数据结构对象  
  17.             MyMessage msg = new MyMessage();  
  18.             msg.setCommand(command);  
  19.             msg.setContents(bytes);  
  20.             out.write(msg);  
  21.             return true;  
  22.     }  
  23. }  



工厂类,很简单。主要是给server端和client端提供使用 

Java代码 

 收藏代码

  1. public class MyCodeFactory implements ProtocolCodecFactory{  
  2.       
  3.     private ProtocolDecoder decoder;  
  4.     private ProtocolEncoder encoder;  
  5.       
  6.     public MyCodeFactory() {  
  7.         decoder = new MyDecoder();  
  8.         encoder = new MyEncoder();  
  9.     }  
  10.   
  11.     @Override  
  12.     public ProtocolEncoder getEncoder(IoSession session) throws Exception {  
  13.         return encoder;  
  14.     }  
  15.   
  16.     @Override  
  17.     public ProtocolDecoder getDecoder(IoSession session) throws Exception {  
  18.         return decoder;  
  19.     }  
  20. }  



写到这里基本上自定义编码解码部分就完成了,下面使用就和其他已有mina提供的 
编码解码filter一样使用了 

首先还是要定义两个handler 

server端handler: 
 

Java代码 

 收藏代码

  1. public class MyServerHandler extends IoHandlerAdapter {  
  2.        @Override  
  3.         public void exceptionCaught( IoSession session, Throwable cause ) throws Exception  
  4.         {  
  5.             cause.printStackTrace();  
  6.             session.close(true);  
  7.         }  
  8.         @Override  
  9.         public void messageReceived( IoSession session, Object message ) throws Exception  
  10.         {     
  11.          //收到了上面解码后的消息  
  12.             MyMessage msg = (MyMessage) message;  
  13.             if(message == null){  
  14.                 //TODO   
  15.             }  
  16.                   
  17.             int cmd = msg.getCommand();  
  18.             String body = new String(msg.getContents());  
  19.             String result = "";  
  20.         //TODO  
  21.         /** 
  22.           根据请求指令的不同,调用后续的业务, 
  23.           然后响应内容到client 
  24.         */  
  25.             System.out.println(msg.getCommand()+"-----"+new String(msg.getContents()));  
  26.             session.write(msg);  
  27.         }  
  28. }  



client端handler 
 

Java代码 

 收藏代码

  1. public class MyClientHandler extends IoHandlerAdapter {  
  2.     @Override  
  3.     public void sessionOpened(IoSession session) throws Exception {  
  4.         //session.write(obj);  
  5.     }  
  6.       
  7.     @Override  
  8.     public void messageReceived(IoSession session, Object message)  
  9.             throws Exception {  
  10.             //收到消息,。。。  
  11.         MyMessage gm = (MyMessage) message;  
  12.         System.out.println(gm.getCommand()+":"+new String(gm.getContents()));  
  13.     }  
  14.       
  15.     @Override  
  16.     public void exceptionCaught(IoSession session, Throwable cause)  
  17.             throws Exception {  
  18.         session.close(true);  
  19.     }  
  20. }  



server端配置: 
 

Java代码 

 收藏代码

  1. IoAcceptor accepter = new NioSocketAcceptor();  
  2. ProtocolCodecFilter coderFilter =   
  3. //使用自定义的编码解码filter  
  4.   new ProtocolCodecFilter(new MyCodeFactory());  
  5. accepter.getFilterChain().addLast("a", new LoggingFilter());  
  6. accepter.getFilterChain().addLast("b",coderFilter);  
  7. //绑定handler  
  8. accepter.setHandler(new MyServerHandler());  
  9.   
  10. accepter.getSessionConfig().setReadBufferSize(2048);  
  11. accepter.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 10);  
  12. accepter.bind(new InetSocketAddress(8484));  


client端配置: 
 

Java代码 

 收藏代码

  1. NioSocketConnector connector = new NioSocketConnector();  
  2. connector.setConnectTimeoutMillis(20000);  
  3. connector.getFilterChain().addLast("codes", new ProtocolCodecFilter(  
  4.         new MyCodeFactory()));  
  5. connector.setHandler(new MyClientHandler());  
  6. ConnectFuture future = connector.connect(new InetSocketAddress("localhost", 8484));  
  7. future.awaitUninterruptibly();  
  8. IoSession session = null;  
  9. session = future.getSession();  
  10.   
  11. MyMessage gm = new MyMessage();  
  12. Map<String, String> map = new HashMap<String, String>();  
  13. gm.setCommand(101);  
  14. map.put("name", "bird");  
  15. map.put("age", "7");  
  16. //JsonUtil json工具类,map转json,随便找个就行  
  17. gm.setContents(JsonUtil.objectToStr(map).getBytes());  
  18. session.write(gm);  
  19.   
  20. connector.dispose();  



运行后server端会打印:1001-----{"name":"c","age":"7"} 
client:1001:{"name":"c","age":"7"} 

都能正确获取到传递的内容。 

转载于:https://my.oschina.net/hejunbinlan/blog/1524725

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值