mina自定义编解码

Mina自定义编解码

协议编解码器是在使用Mina 的时候你最需要关注的对象,因为在网络传输的数据都是二进制数据(byte),而你在程序中面向的是JAVA 对象,这就需要你实现在发送数据时将JAVA 对象编码二进制数据,而接收数据时将二进制数据解码为JAVA 对象(这个可不是JAVA 对象的序列化、反序列化那么简单的事情)

Mina 中的协议编解码器通过过滤器ProtocolCodecFilter 构造,这个过滤器的构造方法需要一个ProtocolCodecFactory,
ProtocolCodecFactory 中有如下两个方法:

复制代码
public interface ProtocolCodecFactory {

ProtocolEncoder getEncoder(IoSession session) throws Exception;

ProtocolDecoder getDecoder(IoSession session) throws Exception;

}
复制代码

ProtocolEncoder是自定义编码器要实现的接口,ProtocolDecoder是自定义解码器要实现的接口。

下面是示例代码:(模拟手机信息的编解码,消息格式;有报头,发送人,接收人,内容长度,内容信息)

MsgObject.java: 消息实体类

复制代码
 1 public class MsgObject {
 2     //发送者
 3     private String sender;
 4     //接收者
 5     private String receiver;
 6     //信息内容
 7     private String content;
 8 
 9     public String getSender() {
10         return sender;
11     }
12 
13     public void setSender(String sender) {
14         this.sender = sender;
15     }
16 
17     public String getReceiver() {
18         return receiver;
19     }
20 
21     public void setReceiver(String receiver) {
22         this.receiver = receiver;
23     }
24 
25     public String getContent() {
26         return content;
27     }
28 
29     public void setContent(String content) {
30         this.content = content;
31     }
32 
33 }
复制代码

 

MessageEncoder.java: 消息编码器 

复制代码
 1 //消息编码器
 2 public class MessageEncoder extends ProtocolEncoderAdapter {
 3     private Charset charset;
 4     
 5     public MessageEncoder(Charset charset)
 6     {
 7         this.charset = charset;
 8     }
 9     
10     @Override
11     public void encode(IoSession arg0, Object arg1, ProtocolEncoderOutput arg2)
12             throws Exception {
13         MsgObject msg = (MsgObject) arg1;
14         //生成字符编码器
15         CharsetEncoder charsetEncoder = charset.newEncoder();
16         //得到要发送对象属性内容,准备进行编码
17         String status = "M sip:wap.fetion.com.cn SIP-C/2.0";
18         String sender = msg.getSender();
19         String receiver = msg.getReceiver();
20         String content = msg.getContent();
21         //开辟一个缓存空间,设置为自动调整大小
22         IoBuffer ioBuffer = IoBuffer.allocate(100);
23         ioBuffer.setAutoExpand(true);
24         //将要发送的信息放入缓存空间
25         //消息头
26         ioBuffer.putString(status + "\n", charsetEncoder);
27         //消息发送者
28         ioBuffer.putString("S: " + sender + "\n", charsetEncoder);
29         //消息接收者
30         ioBuffer.putString("R: " + receiver + "\n", charsetEncoder);
31         //消息内容长度
32         ioBuffer.putString("L: " + content.getBytes(charset).length + "\n", charsetEncoder);
33         //消息内容
34         ioBuffer.putString(content + "\n", charsetEncoder);
35         //编码后的信息已放入ioBuffer中,进行写回
36         ioBuffer.flip();
37         arg2.write(ioBuffer);
38     }
39 
40 } 
复制代码


MessageDecoder.java: 消息解码器

复制代码
 1 //消息解码器
 2 public class MessageDecoder extends CumulativeProtocolDecoder {
 3     private Charset charset;
 4 
 5     public MessageDecoder(Charset charset) {
 6         this.charset = charset;
 7     }
 8 
 9     @Override
10     protected boolean doDecode(IoSession arg0, IoBuffer arg1,
11             ProtocolDecoderOutput arg2) throws Exception {
12         CharsetDecoder charDecoder = charset.newDecoder();
13         IoBuffer buffer = IoBuffer.allocate(100).setAutoExpand(true);
14         // 接收解码后的信息
15         String status = "";
16         String sender = "";
17         String receiver = "";
18         String contentLen = "";
19         String content = "";
20 
21         int textLineNumber = 1;
22         int columnNumber = 0;
23         // 如果缓存区还有消息
24         while (arg1.hasRemaining()) {
25             byte bt = arg1.get();
26             buffer.put(bt);
27             //换行
28             if (bt == 10 && textLineNumber < 5) {
29                 columnNumber++;
30                 if (textLineNumber == 1) {
31                     buffer.flip();
32                     status = buffer.getString(columnNumber, charDecoder);
33                     status = status.substring(0, status.length() - 1);
34                     columnNumber = 0;
35                     buffer.clear();
36                 }
37                 if (textLineNumber == 2) {
38                     buffer.flip();
39                     sender = buffer.getString(columnNumber, charDecoder);
40                     sender = sender.substring(0, sender.length() - 1);
41                     columnNumber = 0;
42                     buffer.clear();
43                 }
44                 if (textLineNumber == 3) {
45                     buffer.flip();
46                     receiver = buffer.getString(columnNumber, charDecoder);
47                     receiver = receiver.substring(0, receiver.length() - 1);
48                     columnNumber = 0;
49                     buffer.clear();
50                 }
51                 if (textLineNumber == 4) {
52                     buffer.flip();
53                     contentLen = buffer.getString(columnNumber, charDecoder);
54                     contentLen = contentLen.substring(0,
55                             contentLen.length() - 1);
56                     columnNumber = 0;
57                     buffer.clear();
58                 }
59                 textLineNumber++;
60             } else if (textLineNumber == 5) {
61                 columnNumber++;
62                 if (columnNumber == Long.parseLong(contentLen.split(": ")[1])) {
63                     buffer.flip();
64                     content = buffer.getString(columnNumber, charDecoder);
65                     textLineNumber++;
66                     break;
67                 }
68             } else {
69                 columnNumber++;
70             }
71 
72         }
73         MsgObject smsObject = new MsgObject();
74         smsObject.setSender(sender.split(": ")[1]);
75         smsObject.setReceiver(receiver.split(": ")[1]);
76         smsObject.setContent(content);
77         arg2.write(smsObject);
78         return false;
79     }
80 }
复制代码

关于IoBuffer的读操作,需要了解一下原理,可参考文章:Mina框架研究(2)

 

MessageProtocolCodecFactory.java: 生成消息编解码器工厂

复制代码
 1 //编解码器生成工产
 2 public class MessageProtocolCodecFactory implements ProtocolCodecFactory {
 3     private ProtocolEncoder encoder;
 4     private ProtocolDecoder decoder;
 5     
 6     public MessageProtocolCodecFactory()
 7     {
 8         this(Charset.forName("UTF-8"));
 9     }
10     
11     public MessageProtocolCodecFactory(Charset charset)
12     {
13         encoder = new MessageEncoder(charset);
14         decoder = new MessageDecoder(charset);
15     }
16     
17     @Override
18     public ProtocolDecoder getDecoder(IoSession arg0) throws Exception {
19         return decoder;
20     }
21 
22     @Override
23     public ProtocolEncoder getEncoder(IoSession arg0) throws Exception {
24         return encoder;
25     }
26 
27 }
复制代码

接着就是调用这些编解码器来进行对象的传输了,服务器端和客户端的主程序编写可参考Mina框架HelloWorld入门

 

温馨提示:
上面的消息解码器( MessageDecoder.java)中的解码考虑的情况是消息一次性从服务器发送过来,但有时消息可能不是一次性从服务器发送过来,而是分成了几次分批过来,这时就会重复调用解码器的deCode()方法,这时状态变量textLineNumber和columnNumber就会被重置,所以要把状态变量保存起来。可能你会想到将状态变量保存在解码器的成员变量中,但是Mina不保证每次调用deCode()方法的都是同一个线程,所以状态变量不是线程安全的。所以要将状态变量保存到IoSession中,因为IoSession用了一个同步的HashMap保存对象。


在IoSession中保存状态变量:

// 保存数据状态对象的key值
    private final AttributeKey CONTEXT = new AttributeKey(getClass(), "context");

通过IoSession.setAttribute和IoSession.getAttribute的保存和得到保存数据的对象
如下:

复制代码
1 private MsgContext getContext(IoSession session) {
2         MsgContext context = (MsgContext) session.getAttribute(CONTEXT);
3         if (null == context) {
4             context = new MsgContext();
5             session.setAttribute(CONTEXT, context);
6         }
7         return context;
8     }
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值