Minaは伝送オブジェクトの符号化を実現する


前言:プロトコルコーデックはMinaを使用するときに最も注目しなければならないオブジェクトです.ネットワークで伝送されるデータはバイナリデータ(byte)であり、プログラムの中でJAVAオブジェクトに向いているため、データを送信するときにJAVAオブジェクトをバイナリデータに符号化し、データを受信するときにバイナリデータをJAVAオブジェクトに復号する必要があります.(注意ここではJAVAオブジェクトのシーケンス化と逆シーケンス化ではありません).
1)、符号化:符号化は、通常のオブジェクトの属性コンテンツを順次バイナリオブジェクトの属性コンテンツに置き換えるプロセスである.
2)、復号化:変換されたバイナリオブジェクトフィールドから通常オブジェクト属性フィールドの内容に変換するプロセス.
1、コーデック工場:符号化と復号実現の呼び出し口を提供する  MinaのプロトコルコーデックはフィルタProtocolCodecFilterによって構築されています.このフィルタの構築方法にはProtocolCodecFactoryが必要です.ProtocolCodecFactoryには次の2つの方法があります.
public interface ProtocolCodecFactory {

     ProtocolEncoder getEncoder(IoSession session) throws Exception;//ProtocolEncoder             

     ProtocolDecoder getDecoder(IoSession session) throws Exception;//ProtocolDecoder             

} 

メッセージングファクトリの例:
//        
  public class MessageProtocolCodecFactory implements ProtocolCodecFactory {
      private ProtocolEncoder encoder;
      private ProtocolDecoder decoder;
      
      public MessageProtocolCodecFactory()
      {
          this(Charset.forName("UTF-8"));
      }
     
     public MessageProtocolCodecFactory(Charset charset)
     {
         encoder = new MessageEncoder(charset);
         decoder = new MessageDecoder(charset);
     }
     
     @Override
     public ProtocolDecoder getDecoder(IoSession arg0) throws Exception {
         return decoder;
     }
 
     @Override
     public ProtocolEncoder getEncoder(IoSession arg0) throws Exception {
         return encoder;
     }

 } 


2、メッセージ伝送対象:伝送データを搭載した実体対象の以下はサンプルコードである:(アナログ携帯電話情報のコーデック、メッセージフォーマット:メッセージヘッダ、送信者、受信者、コンテンツ長、コンテンツ情報)  MsgObject.java:メッセージエンティティクラス
 public class MsgObject {
      //   
      private String sender;
      //   
      private String receiver;
      //    
      private String content;
  
     public String getSender() {
         return sender;
     }
 
     public void setSender(String sender) {
         this.sender = sender;
     }
 
     public String getReceiver() {
         return receiver;
     }
 
     public void setReceiver(String receiver) {
         this.receiver = receiver;
     }
 
     public String getContent() {
         return content;
     }
 
    public void setContent(String content) {
         this.content = content;
    }
} 

3、メッセージエンコーダ:MessageEncoder.java.このクラスはProtocolEncoderを実現するか、ProtocolEncoderAdapterから継承する.
//     
 public class MessageEncoder extends ProtocolEncoderAdapter {
      private Charset charset;
      
     public MessageEncoder(Charset charset){
          this.charset = charset;
      }
      
     @Override
     public void encode(IoSession session, Object message, ProtocolEncoderOutput out)
             throws Exception {
        MsgObject msg = (MsgObject) message;
        //       
         CharsetEncoder charsetEncoder = charset.newEncoder();
        //           ,      
         String status = "M sip:wap.fetion.com.cn SIP-C/2.0";
        String sender = msg.getSender();
        String receiver = msg.getReceiver();
        String content = msg.getContent();
        //        ,         
         IoBuffer ioBuffer = IoBuffer.allocate(100);
        ioBuffer.setAutoExpand(true);
        //             
         //   
         ioBuffer.putString(status + "
", charsetEncoder); // ioBuffer.putString("S: " + sender + "
", charsetEncoder); // ioBuffer.putString("R: " + receiver + "
", charsetEncoder); // ioBuffer.putString("L: " + content.getBytes(charset).length + "
", charsetEncoder); // ioBuffer.putString(content + "
", charsetEncoder); // ioBuffer , ioBuffer.flip(); out.write(ioBuffer); } }

4、メッセージデコーダ:MessageDecoder.java.このクラスはProtocolDecoderを実現するか、ProtocolDecoderAdapterから継承する. 
 //     
  public class MessageDecoder extends ProtocolDecoderAdapter{
      private Charset charset;
  
      public MessageDecoder(Charset charset) {
          this.charset = charset;
      }
  
      @Override
     protected boolean doDecode(IoSession session, IoBuffer in,  ProtocolDecoderOutput out) throws Exception {
         CharsetDecoder charDecoder = charset.newDecoder();
         IoBuffer buffer = IoBuffer.allocate(100).setAutoExpand(true);
         //         
         String status = "";
         String sender = "";
         String receiver = "";
         String contentLen = "";
         String content = "";
 
         int textLineNumber = 1;
         int columnNumber = 0;
         //          
         while (in.hasRemaining()) {
             byte bt = in.get();
             buffer.put(bt);
             //  
             if (bt == 10 && textLineNumber < 5) {
                 columnNumber++;
                 if (textLineNumber == 1) {
                     buffer.flip();
                     status = buffer.getString(columnNumber, charDecoder);
                     status = status.substring(0, status.length() - 1);
                     columnNumber = 0;
                     buffer.clear();
                 }
                 if (textLineNumber == 2) {
                     buffer.flip();
                     sender = buffer.getString(columnNumber, charDecoder);
                     sender = sender.substring(0, sender.length() - 1);
                     columnNumber = 0;
                     buffer.clear();
                 }
                 if (textLineNumber == 3) {
                     buffer.flip();
                     receiver = buffer.getString(columnNumber, charDecoder);
                     receiver = receiver.substring(0, receiver.length() - 1);
                     columnNumber = 0;
                     buffer.clear();
                 }
                 if (textLineNumber == 4) {
                     buffer.flip();
                     contentLen = buffer.getString(columnNumber, charDecoder);
                     contentLen = contentLen.substring(0,
                             contentLen.length() - 1);
                     columnNumber = 0;
                     buffer.clear();
                 }
                 textLineNumber++;
             } else if (textLineNumber == 5) {
                 columnNumber++;
                 if (columnNumber == Long.parseLong(contentLen.split(": ")[1])) {
                     buffer.flip();
                     content = buffer.getString(columnNumber, charDecoder);
                     textLineNumber++;
                     break;
                 }
             } else {
                 columnNumber++;
             }
 
         }
         MsgObject smsObject = new MsgObject();
         smsObject.setSender(sender.split(": ")[1]);
         smsObject.setReceiver(receiver.split(": ")[1]);
         smsObject.setContent(content);
         out.write(smsObject);
         return false;
     }
 } 

5、Minaコーデックに知っておくべきこと
1)、Mina IoBufferの読み取り操作を理解することが望ましい.  2)、フィルタ内でこれらのコーデックを呼び出してオブジェクトの伝送を行い、サーバ側とクライアント側のメインプログラムの作成を行う.  3)、オブジェクト復号化をバッチで実現するかどうかを考える
上記のメッセージデコーダ(MessageDecoder.java)における復号は、メッセージが一度にサーバから送信されることを考慮しているが、メッセージが一度にサーバから送信されるのではなく、数回に分けてバッチされる場合があり、デコーダのdeCode()メソッドが繰り返し呼び出され、状態変数textLineNumberとcolumnNumberがリセットされ、だから状態変数を保存します.状態変数をデコーダのメンバー変数に保存することを考えるかもしれませんが、MinaはdeCode()メソッドを呼び出すたびに同じスレッドであることを保証しません.したがって、状態変数はスレッドでは安全ではありません.したがって、状態変数をIoSessionに保存するには、IoSessionが同期HashMapを使用してオブジェクトを保存しているため(クライアントとサービス側で開始されたセッションは同じプロセスではないので、sessionは同じsessionではなく、ここではMinaがイベント駆動非同期のAPIであることを示すことができる).
以下は、IoSessionに保存されている状態変数です. 
//          key 
private final AttributeKey CONTEXT = new AttributeKey(getClass(), "context"); 
 

//  IoSession.setAttribute IoSession.getAttribute             
 private MsgContext getContext(IoSession session) {
         MsgContext context = (MsgContext) session.getAttribute(CONTEXT);
         if (null == context) {
             context = new MsgContext();
             session.setAttribute(CONTEXT, context);
         }
         return context;
  }