public class SocketServerDecoder extends CumulativeProtocolDecoder {
private static final Logger log = Logger.getLogger(SocketServerDecoder.class);
public static final boolean ifPrintDebugInfo=false;
private Charset charset =null;
private static final String ATTRIBUTE_NAME="HelperMsgInfo";
public SocketServerDecoder(Charset charset) {
this.charset=charset;
log.debug("Server端#SocketServerDecoder构造方法,当前线程:"+Thread.currentThread().getId());
}
@Override
protected boolean doDecode(IoSession session, IoBuffer ioBuffer,
ProtocolDecoderOutput out) throws Exception {
ioBuffer.order(ByteOrder.LITTLE_ENDIAN);
log.debug("Server端#doDecode#剩余客户端消息大小:"+ioBuffer.remaining());
sysPrintLn("Server端#doDecode#ioBuffer读到剩余客户端消息大小:"+ioBuffer.remaining());
MessageInfo hmi=null;
String attrStr=ATTRIBUTE_NAME+session.getId();
Object o=session.getAttribute(attrStr);
if(null!=o && (o instanceof MessageInfo)){
hmi=(MessageInfo)o;
}
//修改缓冲区的字节顺序为little-endian,按照此顺序,多字节值的字节顺序是从最低有效位到最高有效位的。
if(null==hmi){
sysPrintLn("null==hmi");
if(ioBuffer.remaining()>4){
sysPrintLn("ioBuffer.remaining()>4");
hmi=new MessageInfo();
short bodyLength= ioBuffer.getShort();
short msgIdentify=ioBuffer.getShort();
hmi.setMsgBodySize(bodyLength);
hmi.setMsgIdentify(msgIdentify);
sysPrintLn("ioBuffer.position [null==hmi]:"+ioBuffer.position());
sysPrintLn("bodyLength:"+bodyLength);
sysPrintLn("msgIdentify:"+msgIdentify);
session.setAttribute(attrStr,hmi);
sysPrintLn(" [null==hmi]将再次调用当前解码方法!");
return true;
}else{
sysPrintLn("ioBuffer.remaining()<=4");
sysPrintLn("将继续接收!");
return false;
}
}else{
sysPrintLn(" [null!=hmi]");
sysPrintLn("剩余byte大小1:"+ioBuffer.remaining());
if (ioBuffer.remaining() >= hmi.getMsgBodySize()) {
sysPrintLn("ioBuffer.remaining() >= hmi.getMsgbodySize()!");
/*
* 检查缓冲区的可用字节数是否大于等于消息体长度,即是否读取到消息体了。
*/
byte[] messageBody = new byte[hmi.getMsgBodySize()]; // 创建定长的数组存放消息体
ioBuffer.get(messageBody); // 从缓冲区中读取bodyLength字节的数据填充进数组
String msgbody = new String(messageBody,charset); // 设置请求的消息体
sysPrintLn("msgbody:"+msgbody);
hmi.setMsgBody(msgbody);
/*
* 将session对象的“HelperMsgInfo”键及其对应的属性值移除从而:
* 1、将bodySize键设置成无值状态,代表消息体已经解析完成。再次进入等待解析消息头阶段
* 2、释放存储“HelperMsgInfo”键的属性值占用的内存。
*/
session.removeAttribute(attrStr);
/*
* 将解码后生成的请求对象对象抛给位于应用层的Handler处理,或者抛给下一层解码器(如果存在)。
*/
out.write(hmi);
/*
* 因为当一条完整消息解析完成后,这时缓冲区内可能还有足够的积累数据可以继续解析下一条消息(也可能没有),
* 返回true使框架再次调用doDecode方法 。
* 即使缓冲区内没有足够的数据了,也应该留给下次调用doDecode方法时去判断。
*/
sysPrintLn("[null!=hmi]将再次调用当前解码方法!");
return true;
} else {
sysPrintLn("ioBuffer.position *****:"+ioBuffer.position());
sysPrintLn("剩余byte大小 ****:"+ioBuffer.remaining());
sysPrintLn("ioBuffer.remaining() < hmi.getMsgbodySize()!");
/*
* 如果缓冲区内可用字节个数不足以构成完整的消息体,
* 直接返回false告诉框架不要再回调doDecode方法,
* 直到网络获取到数据压进缓冲区时再调用
*/
sysPrintLn("将继续接收!");
return false;
}
}
}
private void sysPrintLn(String s){
if(SocketServerDecoder.ifPrintDebugInfo){
System.out.println(s);
}
}
}
private static final Logger log = Logger.getLogger(SocketServerDecoder.class);
public static final boolean ifPrintDebugInfo=false;
private Charset charset =null;
private static final String ATTRIBUTE_NAME="HelperMsgInfo";
public SocketServerDecoder(Charset charset) {
this.charset=charset;
log.debug("Server端#SocketServerDecoder构造方法,当前线程:"+Thread.currentThread().getId());
}
@Override
protected boolean doDecode(IoSession session, IoBuffer ioBuffer,
ProtocolDecoderOutput out) throws Exception {
ioBuffer.order(ByteOrder.LITTLE_ENDIAN);
log.debug("Server端#doDecode#剩余客户端消息大小:"+ioBuffer.remaining());
sysPrintLn("Server端#doDecode#ioBuffer读到剩余客户端消息大小:"+ioBuffer.remaining());
MessageInfo hmi=null;
String attrStr=ATTRIBUTE_NAME+session.getId();
Object o=session.getAttribute(attrStr);
if(null!=o && (o instanceof MessageInfo)){
hmi=(MessageInfo)o;
}
//修改缓冲区的字节顺序为little-endian,按照此顺序,多字节值的字节顺序是从最低有效位到最高有效位的。
if(null==hmi){
sysPrintLn("null==hmi");
if(ioBuffer.remaining()>4){
sysPrintLn("ioBuffer.remaining()>4");
hmi=new MessageInfo();
short bodyLength= ioBuffer.getShort();
short msgIdentify=ioBuffer.getShort();
hmi.setMsgBodySize(bodyLength);
hmi.setMsgIdentify(msgIdentify);
sysPrintLn("ioBuffer.position [null==hmi]:"+ioBuffer.position());
sysPrintLn("bodyLength:"+bodyLength);
sysPrintLn("msgIdentify:"+msgIdentify);
session.setAttribute(attrStr,hmi);
sysPrintLn(" [null==hmi]将再次调用当前解码方法!");
return true;
}else{
sysPrintLn("ioBuffer.remaining()<=4");
sysPrintLn("将继续接收!");
return false;
}
}else{
sysPrintLn(" [null!=hmi]");
sysPrintLn("剩余byte大小1:"+ioBuffer.remaining());
if (ioBuffer.remaining() >= hmi.getMsgBodySize()) {
sysPrintLn("ioBuffer.remaining() >= hmi.getMsgbodySize()!");
/*
* 检查缓冲区的可用字节数是否大于等于消息体长度,即是否读取到消息体了。
*/
byte[] messageBody = new byte[hmi.getMsgBodySize()]; // 创建定长的数组存放消息体
ioBuffer.get(messageBody); // 从缓冲区中读取bodyLength字节的数据填充进数组
String msgbody = new String(messageBody,charset); // 设置请求的消息体
sysPrintLn("msgbody:"+msgbody);
hmi.setMsgBody(msgbody);
/*
* 将session对象的“HelperMsgInfo”键及其对应的属性值移除从而:
* 1、将bodySize键设置成无值状态,代表消息体已经解析完成。再次进入等待解析消息头阶段
* 2、释放存储“HelperMsgInfo”键的属性值占用的内存。
*/
session.removeAttribute(attrStr);
/*
* 将解码后生成的请求对象对象抛给位于应用层的Handler处理,或者抛给下一层解码器(如果存在)。
*/
out.write(hmi);
/*
* 因为当一条完整消息解析完成后,这时缓冲区内可能还有足够的积累数据可以继续解析下一条消息(也可能没有),
* 返回true使框架再次调用doDecode方法 。
* 即使缓冲区内没有足够的数据了,也应该留给下次调用doDecode方法时去判断。
*/
sysPrintLn("[null!=hmi]将再次调用当前解码方法!");
return true;
} else {
sysPrintLn("ioBuffer.position *****:"+ioBuffer.position());
sysPrintLn("剩余byte大小 ****:"+ioBuffer.remaining());
sysPrintLn("ioBuffer.remaining() < hmi.getMsgbodySize()!");
/*
* 如果缓冲区内可用字节个数不足以构成完整的消息体,
* 直接返回false告诉框架不要再回调doDecode方法,
* 直到网络获取到数据压进缓冲区时再调用
*/
sysPrintLn("将继续接收!");
return false;
}
}
}
private void sysPrintLn(String s){
if(SocketServerDecoder.ifPrintDebugInfo){
System.out.println(s);
}
}
}