设为首页 收藏本站
查看: 630|回复: 0

[经验分享] apache mina第三发-自定义通信协议(下)

[复制链接]

尚未签到

发表于 2017-1-11 06:40:46 | 显示全部楼层 |阅读模式
  在实际的网络通信中,阻塞是很可能发生的。那我们可以设想如果我们的一条消息被分成了两截,分两次发来,那么我们的解码器中的doDecode方法被先后调用两次,在前一次中不足以解码出一条完整的信息,而在后一次调用中我们也不知道前面一次解码到了哪一步。这个问题我们通过引入一个上下文的概念来解决。
  在doDecode方法中有一个IoSession类型的参数,它很类似于Web中的Session,拥有一个Map,用键值对的形式来存储参数。一个IoSession可以类比为阻塞IO中的一个连接,我们可以把解码过程中用到的所有变量都存在里面。为了程序的结构良好,我们把所有变量包装成一个Context对象,变量的初始化都放在Context的构造函数里,原来对变量的操作也就成了对Context的操作。改造后的解码器类如下所示

package mina.common;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.AttributeKey;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.CumulativeProtocolDecoder;
import org.apache.mina.filter.codec.ProtocolDecoderOutput;
/**
* 解码器类
* @author 尹定宇
* @Email 768166775@qq.com
* @version 2013-5-2 上午10:10:03
* @info
*/
public class CmccSipcDecoder extends CumulativeProtocolDecoder {
//字符集
private final Charset charset;
//上下文的key
private final AttributeKey CONTEXT = new AttributeKey(getClass(),"context");
//构造方法
public CmccSipcDecoder(Charset charset) {
this.charset = charset;
}

@Override
protected boolean doDecode(IoSession session, IoBuffer in,
ProtocolDecoderOutput out) throws Exception {
//得到上下文
Context ctx = getContext(session);
//设置缓冲区,初始长度为100,可以自动调整长度
IoBuffer buffer = ctx.getInnerBuffer();
//获得一个字符编码器
CharsetDecoder cd = charset.newDecoder();
//表示一行中第几个字节
int matchCount = ctx.getMatchCount();
//初始化几个字符串
String statusLine = ctx.getStatusLine(),
sender = ctx.getSender(),
receiver = ctx.getReceiver(),
length = ctx.getLength(),
sms = ctx.getSms();
//表示第几行
int line = ctx.getLine();
//从输入流中读取
while (in.hasRemaining()) {
byte b = in.get();
//游标前移
matchCount++;
buffer.put(b);
//读到了换行符,而且不是第五行
if (b == 10 && line < 4) {
//如果是第一行,得到状态行字符串
if (line == 0) {
buffer.flip();
statusLine = buffer.getString(matchCount, cd);
statusLine = statusLine.substring(0,
statusLine.length() - 1);
matchCount = 0;
buffer.clear();
ctx.setStatusLine(statusLine);
}
//发送方
if (line == 1) {
buffer.flip();
sender = buffer.getString(matchCount, cd);
sender = sender.substring(0, sender.length() - 1);
matchCount = 0;
buffer.clear();
ctx.setSender(sender);
}
//接收方
if (line == 2) {
buffer.flip();
receiver = buffer.getString(matchCount, cd);
receiver = receiver.substring(0, receiver.length()-1);
matchCount = 0;
buffer.clear();
ctx.setReceiver(receiver);
}
//短信的长度
if (line == 3) {
buffer.flip();
length = buffer.getString(matchCount, cd);
length = length.substring(0, length.length() - 1);
matchCount = 0;
buffer.clear();
ctx.setLength(length);
}
//行数递增
line++;
} else if (line == 4) {//如果是第五行,则读取短信内容

//当读到的字节数等于上一行所定义的短信长度时
if (matchCount == Long.parseLong(length.split(": ")[1]))
{
buffer.flip();
sms = buffer.getString(matchCount, cd);
ctx.setSms(sms);
ctx.setMatchCount(matchCount);
ctx.setLine(line);
break;
}
}
ctx.setMatchCount(matchCount);
ctx.setLine(line);
}
if(ctx.getLine()==4&&Long.parseLong(ctx.getLength().split(":")[1])==ctx.getMatchCount()){
SmsObject smsObject = new SmsObject();
smsObject.setSender(sender.split(": ")[1]);
smsObject.setReceiver(receiver.split(": ")[1]);
smsObject.setMessage(sms);
out.write(smsObject);
ctx.reset();
return true;
}else{
return false;
}
}
private Context getContext(IoSession session){
Context context = (Context)session.getAttribute(CONTEXT);
if(context == null){
context = new Context();
session.setAttribute(CONTEXT, context);
}
return context;
}
/**
* 存储上下文的内部类
* @author 尹定宇
* @Email 768166775@qq.com
* @version 2013-5-7 下午12:57:02
* @info
*/
private class Context{
private final IoBuffer innerBuffer;
private String statusLine = "";
private String sender = "";
private String receiver = "";
private String length = "";
private String sms = "";
public Context(){
innerBuffer = IoBuffer.allocate(100).setAutoExpand(true);
}
private int matchCount = 0;
private int line = 0;
public String getStatusLine() {
return statusLine;
}
public void setStatusLine(String statusLine) {
this.statusLine = statusLine;
}
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 getLength() {
return length;
}
public void setLength(String length) {
this.length = length;
}
public String getSms() {
return sms;
}
public void setSms(String sms) {
this.sms = sms;
}
public int getMatchCount() {
return matchCount;
}
public void setMatchCount(int matchCount) {
this.matchCount = matchCount;
}
public int getLine() {
return line;
}
public void setLine(int line) {
this.line = line;
}

public void reset(){
this.innerBuffer.clear();
this.matchCount = 0;
this.line = 0;
this.statusLine = "";
this.sender = "";
this.receiver = "";
this.length = "";
this.sms = "";
}
public IoBuffer getInnerBuffer() {
return innerBuffer;
}
}
}

  有一点特别需要我们注意,就是所有变量都来自Context的get方法,基本类型的变量改变之后别忘了把它们set回去,当然如果你把变量完全隐藏起来,只把外界可能用到的操作对外提供接口,那就更好了。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-326623-1-1.html 上篇帖子: Apache + JK + Tomcat + 虚拟主机 架构的整合配置方式 下篇帖子: 使用apache的ant.jar进行压缩/解压缩文件
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表