一、定义协议实体

 

[java] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. import java.nio.charset.Charset;  
  2.   
  3. /** 
  4.  * 自定义协议的消息体 
  5.  */  
  6. public class MyMsg {  
  7.     /** 
  8.      * 消息长度 
  9.      */  
  10.     private Integer lenth;  
  11.   
  12.     /** 
  13.      * 发送人 
  14.      */  
  15.     private Long sender;  
  16.   
  17.     /** 
  18.      * 接收人 
  19.      */  
  20.     private Long receiver;  
  21.   
  22.     /** 
  23.      * 消息内容 
  24.      */  
  25.     private String content;  
  26.       
  27.     public MyMsg() {  
  28.           
  29.     }  
  30.   
  31.     public Long getSender() {  
  32.         return sender;  
  33.     }  
  34.   
  35.     public void setSender(Long sender) {  
  36.         this.sender = sender;  
  37.     }  
  38.   
  39.     public Long getReceiver() {  
  40.         return receiver;  
  41.     }  
  42.   
  43.     public void setReceiver(Long receiver) {  
  44.         this.receiver = receiver;  
  45.     }  
  46.   
  47.     public String getContent() {  
  48.         return content;  
  49.     }  
  50.   
  51.     public void setContent(String content) {  
  52.         this.content = content;  
  53.     }  
  54.   
  55.     /** 
  56.      * 先计算长度,再返回。这里长度包含长度本身的字节 
  57.      */  
  58.     public Integer getLenth() {  
  59.           
  60.         this.lenth = 4 + 8*2 + this.content.getBytes(Charset.forName("utf-8")).length;  
  61.           
  62.         return lenth;  
  63.     }  
  64.   
  65.     public MyMsg(Long sender, Long receiver, String content) {  
  66.         this.sender = sender;  
  67.         this.receiver = receiver;  
  68.         this.content = content;  
  69.     }  
  70.   
  71.     @Override  
  72.     public String toString() {  
  73.         return "MyMsg [lenth=" + this.getLenth() + ", sender=" + sender + ", receiver="  
  74.                 + receiver + ", content=" + content + "]";  
  75.     }  
  76.   
  77. }  

二、定义编解码器

 

    1、编码器

 

[java] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. import java.nio.charset.Charset;  
  2. import java.nio.charset.CharsetEncoder;  
  3. import org.apache.mina.core.buffer.IoBuffer;  
  4. import org.apache.mina.core.session.IoSession;  
  5. import org.apache.mina.filter.codec.ProtocolEncoderAdapter;  
  6. import org.apache.mina.filter.codec.ProtocolEncoderOutput;  
  7.   
  8. /** 
  9.  *  编码器  
  10.  */  
  11. public class MyEncoder extends ProtocolEncoderAdapter {  
  12.   
  13.     @Override  
  14.     public void encode(IoSession session, Object message, ProtocolEncoderOutput encoderOutput)  
  15.             throws Exception {  
  16.   
  17.         CharsetEncoder ce = Charset.forName("utf-8").newEncoder();  
  18.           
  19.         MyMsg msg = (MyMsg) message;  
  20.           
  21.         //  Mina IoBuffer  
  22.         IoBuffer buffer = IoBuffer.allocate(100).setAutoExpand(true);  
  23.           
  24.         buffer.putInt(msg.getLenth());  
  25.         buffer.putLong(msg.getSender());  
  26.         buffer.putLong(msg.getReceiver());  
  27.           
  28.         //  有多个可变长度的属性时,可约定通过定义可变属性的最大长度(多余截取不足补齐)或put之前put其长度等方式处理  
  29.         buffer.putString(msg.getContent(), ce);  
  30.           
  31.         buffer.flip();  
  32.           
  33.         encoderOutput.write(buffer);  
  34.           
  35.     }  
  36.   
  37. }  

    2、解码器

 

 

[java] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. import java.nio.charset.Charset;  
  2. import java.nio.charset.CharsetDecoder;  
  3. import org.apache.mina.core.buffer.IoBuffer;  
  4. import org.apache.mina.core.session.IoSession;  
  5. import org.apache.mina.filter.codec.CumulativeProtocolDecoder;  
  6. import org.apache.mina.filter.codec.ProtocolDecoderOutput;  
  7.   
  8. /** 
  9.  *  解码器可继承ProtocolEncoderAdapter,但它不利于处理粘包的情况 
  10.  */  
  11. public class MyDecoder extends CumulativeProtocolDecoder {  
  12.       
  13.      @Override  
  14.     protected boolean doDecode(IoSession session, IoBuffer buffer, ProtocolDecoderOutput decoderOutput)   
  15.             throws Exception {  
  16.         CharsetDecoder de = Charset.forName("utf-8").newDecoder();  
  17.   
  18.         /** 
  19.          * 这里,如果长度不够20字节,就认为这条消息还没有累积完成 
  20.          */  
  21.         if(buffer.remaining() < 20){  
  22.             /** 
  23.              *      停止调用decode,但如果还有数据没有读取完,将含有剩余数据的IoBuffer保存到IoSession中, 
  24.              *  当有新数据包来的时候再和新的合并后再调用decoder解码 
  25.              *      注意:没有消费任何数据时不能返回true,否则会抛出异常 
  26.              */  
  27.             return false;  
  28.               
  29.         }else{  
  30.               
  31.             int length = buffer.getInt();  
  32.               
  33.             MyMsg msg = new MyMsg();  
  34.               
  35.             msg.setSender(buffer.getLong());  
  36.             msg.setReceiver(buffer.getLong());  
  37.               
  38.             //  注意:20 = 消息长度的字节 + 发送人和接收人的字节  
  39.             msg.setContent(buffer.getString(length - 20, de));  
  40.               
  41.             decoderOutput.write(msg);  
  42.               
  43.             /** 
  44.              *  CumulativeProtocolDecoder会再次调用decoder,并把剩余的数据发下来继续解码 
  45.              */  
  46.             return true;  
  47.         }  
  48.     }  
  49.   
  50. }  

    3、编解码工厂

 

 

[java] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. import org.apache.mina.core.session.IoSession;  
  2. import org.apache.mina.filter.codec.ProtocolCodecFactory;  
  3. import org.apache.mina.filter.codec.ProtocolDecoder;  
  4. import org.apache.mina.filter.codec.ProtocolEncoder;  
  5.   
  6. /** 
  7.  *  编解码工厂 
  8.  */  
  9. public class MyCoderFactory implements ProtocolCodecFactory{  
  10.       
  11.     private MyDecoder decoder;  
  12.     private MyEncoder encoder;  
  13.   
  14.     public MyCoderFactory() {  
  15.         this.decoder = new MyDecoder();  
  16.         this.encoder = new MyEncoder();  
  17.     }  
  18.   
  19.     @Override  
  20.     public ProtocolDecoder getDecoder(IoSession session) throws Exception {  
  21.         return decoder;  
  22.     }  
  23.   
  24.     @Override  
  25.     public ProtocolEncoder getEncoder(IoSession session) throws Exception {  
  26.         return encoder;  
  27.     }  
  28.   
  29. }  

三、服务器端

 

    1、运行类

 

[java] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. import java.io.IOException;  
  2. import java.net.InetSocketAddress;  
  3. import java.net.SocketAddress;  
  4. import org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder;  
  5. import org.apache.mina.core.service.IoAcceptor;  
  6. import org.apache.mina.core.session.IdleStatus;  
  7. import org.apache.mina.filter.codec.ProtocolCodecFilter;  
  8. import org.apache.mina.filter.logging.LoggingFilter;  
  9. import org.apache.mina.transport.socket.nio.NioSocketAcceptor;  
  10.   
  11. public class ServerMain {  
  12.       
  13.     public static void main(String[] args) throws IOException {  
  14.           
  15.         //  在服务器端创建一个监听连接的接收器 基于tcp/ip  
  16.         IoAcceptor acceptor = new NioSocketAcceptor();  
  17.           
  18.         //  绑定的端口  
  19.         SocketAddress address = new InetSocketAddress("localhost", 8888);  
  20.           
  21.         //   获取过滤器链  
  22.         DefaultIoFilterChainBuilder chain = acceptor.getFilterChain();  
  23.           
  24.         //  添加日志过滤器  
  25.         chain.addLast("logger", new LoggingFilter());  
  26.           
  27.         // 配置自定义的编解码器   
  28.         chain.addLast("mycodec", new ProtocolCodecFilter(new MyCoderFactory()));  
  29.           
  30.         //  添加数据处理的处理器  
  31.         acceptor.setHandler(new ServerHandler());  
  32.           
  33.         //  进行配置信息的设置       
  34.         acceptor.getSessionConfig().setReadBufferSize(100);       
  35.         acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 10);   
  36.           
  37.         //  绑定服务器端口   
  38.         acceptor.bind(address);  
  39.           
  40.         System.out.println("服务器开始在 8888 端口监听.......");  
  41.           
  42.     }  
  43. }  

    2、Handler

 

 

[java] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. import org.apache.mina.core.service.IoHandlerAdapter;  
  2. import org.apache.mina.core.session.IdleStatus;  
  3. import org.apache.mina.core.session.IoSession;  
  4.   
  5. public class ServerHandler extends IoHandlerAdapter{  
  6.   
  7.     /** 
  8.      *  接受消息 
  9.      */  
  10.     public void messageReceived(IoSession session, Object message)  
  11.             throws Exception {  
  12.         MyMsg msg = (MyMsg) message;  
  13.         System.out.println("服务器端接收到的消息:" + msg);  
  14.           
  15.         //  返回一个消息给客户端  
  16.         msg = new MyMsg(10000L, 10001L, "你好,这是来自服务器的应答!");  
  17.         session.write(msg);  
  18.     }  
  19.   
  20.     /** 
  21.      *  发送消息 
  22.      */  
  23.     public void messageSent(IoSession session, Object message) throws Exception {  
  24.         System.out.println("服务器端开始发送消息...");  
  25.         super.messageSent(session, message);  
  26.     }  
  27.   
  28.     /** 
  29.      *  会话开启 
  30.      */  
  31.     public void sessionOpened(IoSession session) throws Exception {  
  32.         System.out.println("服务端会话已打开...");  
  33.         super.sessionOpened(session);  
  34.     }  
  35.   
  36.     /** 
  37.      *  异常处理 
  38.      */  
  39.     public void exceptionCaught(IoSession session, Throwable cause)  
  40.             throws Exception {  
  41.         System.out.println("服务端发生异常了...");  
  42.         cause.printStackTrace();  
  43.     }  
  44.   
  45.     /** 
  46.      *  会话关闭 
  47.      */  
  48.     public void sessionClosed(IoSession session) throws Exception {  
  49.         System.out.println("服务端会话已关闭...");  
  50.         super.sessionClosed(session);  
  51.     }  
  52.   
  53.     /** 
  54.      *  会话创建 
  55.      */  
  56.     public void sessionCreated(IoSession session) throws Exception {  
  57.         System.out.println("服务端会话已创建...");  
  58.         super.sessionCreated(session);  
  59.     }  
  60.   
  61.     /** 
  62.      *  连接空闲 
  63.      */  
  64.     public void sessionIdle(IoSession session, IdleStatus status)  
  65.             throws Exception {  
  66.         System.out.println("服务端连接空闲中...");  
  67.         super.sessionIdle(session, status);  
  68.     }  
  69. }  

四、客户端

 

    1、连接类

 

[java] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. import java.net.InetSocketAddress;  
  2. import java.net.SocketAddress;  
  3. import org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder;  
  4. import org.apache.mina.core.future.ConnectFuture;  
  5. import org.apache.mina.filter.codec.ProtocolCodecFilter;  
  6. import org.apache.mina.filter.logging.LoggingFilter;  
  7. import org.apache.mina.transport.socket.nio.NioSocketConnector;  
  8.   
  9. public class ClientMain {  
  10.     public static void main(String[] args) {  
  11.           
  12.         //  创建客户端连接器 基于tcp/ip  
  13.         NioSocketConnector connector = new NioSocketConnector();  
  14.           
  15.         //  连接的地址和端口  
  16.         SocketAddress address = new InetSocketAddress("localhost",8888);  
  17.   
  18.         //  获取过滤器链  
  19.         DefaultIoFilterChainBuilder chain = connector.getFilterChain();  
  20.       
  21.         //  配置日志过滤器和自定义编解码器  
  22.         chain.addLast("logger", new LoggingFilter());  
  23.         chain.addLast("mycodec",new ProtocolCodecFilter(new MyCoderFactory()));  
  24.       
  25.         //  添加处理器  
  26.         connector.setHandler(new ClientHandler());  
  27.           
  28.         // 连接到服务器   
  29.         ConnectFuture future = connector.connect(address);  
  30.       
  31.         //  等待连接创建完成  
  32.         future.awaitUninterruptibly();  
  33.           
  34.         //  会话创建后发送消息到服务器  
  35.         MyMsg msg = new MyMsg(10001L, 10000L, "你好,这是来自客户端的请求!");  
  36.         future.getSession().write(msg);  
  37.       
  38.         //  等待28000毫秒后连接断开  
  39.         future.getSession().getCloseFuture().awaitUninterruptibly(28000);  
  40.   
  41.         //  关闭连接  
  42.         connector.dispose();  
  43.       
  44.     }  
  45. }  

    2、Handler

 

 

[java] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. import org.apache.mina.core.service.IoHandlerAdapter;  
  2. import org.apache.mina.core.session.IoSession;  
  3.   
  4. public class ClientHandler extends IoHandlerAdapter{  
  5.   
  6.     /** 
  7.      *  接收消息 
  8.      */  
  9.     public void messageReceived(IoSession session, Object message)  
  10.             throws Exception {  
  11.         System.out.println("客户端接收到的消息:" + (MyMsg)message);  
  12.     }  
  13.   
  14.     /** 
  15.      *  发送消息 
  16.      */  
  17.     public void messageSent(IoSession session, Object message) throws Exception {  
  18.         System.out.println("客户端发送消息...");  
  19.         super.messageSent(session, message);  
  20.           
  21.     }  
  22.   
  23.     /** 
  24.      *  会话创建 
  25.      */  
  26.     public void sessionOpened(IoSession session) throws Exception {  
  27.           
  28.         System.out.println("客户端已经连接到了服务器...");  
  29.           
  30.     }  
  31.   
  32.     /** 
  33.      *  会话关闭 
  34.      */  
  35.     public void sessionClosed(IoSession session) throws Exception {  
  36.         System.out.println("连接关闭...");  
  37.         super.sessionClosed(session);  
  38.     }  
  39.       
  40. }  

五、结果

    1、服务器端

        

    2、客户端