一、编码器:将要发送的数据转化成byte[] 进行传输
- 自定义编码器的实现:
package filter;
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;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import protocal.ProtocalPackage;
public class TestEnCoder extends ProtocolEncoderAdapter{
//用于打印日志信息
private final static Logger log = LoggerFactory
.getLogger(ProtocalEncoder.class);
//编码 将数据包转成字节数组
@Override
public void encode(IoSession session, Object message, ProtocolEncoderOutput out) throws Exception {
ProtocalPackage value = (ProtocalPackage) message;
//根据报文长度开辟空间
IoBuffer buff = IoBuffer.allocate(value.getLength());
//设置为可自动扩展空间
buff.setAutoExpand(true);
//将报文中的信息添加到buff中
buff.putInt(value.getLength());
if(value.getContent() != null) {
buff.put(value.getContent().getBytes());
}
buff.flip();
//将报文发送出去
out.write(buff);
}
}
二、解码器:将收到的byte[] 按照协议还原成数据
-
解码器需要解决的问题:网络通信中经常会遇到数据包丢失(丢包),数据包残缺(半包),还有粘包问题。
-
具体实现代码,并解决上述问题:
package filter;
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 org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import protocal.DeviceDataProtocal;
import protocal.HeartbeatProtocal;
import protocal.LoginRequestProtocol;
import protocal.LoginResponseProtocal;
public class TestDecoder extends CumulativeProtocolDecoder{
//打印日志信息
private final static Logger log = LoggerFactory
.getLogger(ProtocalDecoder.class);
@Override
protected boolean doDecode(IoSession session, IoBuffer in, ProtocolDecoderOutput out) throws Exception {
int packHeadLenth = 4; //包头长度(int 的长度) 根据自定义协议的包头的长度
if(in.remaining() > packHeadLenth){ //说明缓冲区中有数据
in.mark();//标记当前position,以便后继的reset操作能恢复position位置
//获取数据包长度
int len = in.getInt();
log.info("len = "+len);
//上面的get会改变remaining()的值
if(in.remaining() <len - packHeadLenth) {
//内容不够, 重置position到操作前,进行下一轮接受新数据
in.reset();
return false;
}else{
//内容足够
in.reset(); //重置回复position位置到操作前
byte[] packArray = new byte[len];
in.get(packArray, 0, len); //获取整条报文
//根据自己需要解析接收到的东西 我的例子 把收到的报文转成String
String str = new String(packArray);
out.write(str); //发送出去 就算完成了
if(in.remaining() > 0){//如果读取一个完整包内容后还粘了包,就让父类再调用一次,进行下一次解析
return true;
}
}
}
return false; //处理成功
}
}
三、实现编解码器工厂类:
package filter;
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 TestFactory implements ProtocolCodecFactory{
private final TestDecoder decoder;
private final TestEnCoder encoder;
//构造
public TestFactory() {
encoder = new TestEnCoder();
decoder = new TestDecoder();
}
@Override
public ProtocolDecoder getDecoder(IoSession arg0) throws Exception {
// TODO Auto-generated method stub
return decoder;
}
@Override
public ProtocolEncoder getEncoder(IoSession arg0) throws Exception {
// TODO Auto-generated method stub
return encoder;
}
}
四、在服务端和客户端中的调用:
//connector 是 IoConnector 的对象
connector.getFilterChain().addLast("coderc", new ProtocolCodecFilter(
new TestFactory() ));
网友评论