Promela BCL-6 B4.0 Protocol [Incomplete]

本文介绍了一种基于PROMELA的BCL可靠性协议版本4.0的验证模型。该模型通过采用集合点通信方式,允许丢包并实现队列自动重发机制。同时,模拟了传输介质中的丢包、包失序及延迟阻塞现象。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

/*
*PROMELAValidationModel
*协议层验证
*
*验证BCL可靠性协议Bversion4.0
*
*Yuhuang
*2007-7-27
*/





/*
*本版本特点:采用集合点来通信,允许CHK、RTT、ACK、DATA丢包,实现了队列自动重发。
*加入了对传输介质的模拟。介质可以丢包,导致包失序。
*加入了对传输介质中存在延迟阻塞的模拟。包可以失序。
*
*加入对CHK的语义实现、接收方向发送方的失序模拟。
*/






/*
*测试记录:
*WIN=5QSIZE=2跑了大约_秒钟
*WIN=7QSIZE=3跑了大约_分钟
*WIN=9QSIZE=4???
*/





/**************数据结构定义*************/


/*序号范围定义*/
#defineWIN7
/*
发送队列大小定义*/
#defineQSIZE3
/*
Note:上面是比较保险的做法:WIN=QSIZE*2+1*/

/*消息类型定义*/
mtype
={ACK,DATA,RRT,CHK}


/*
*{ACK|RRT,res|version,seqno}
*/
chansevts
=[0]of{mtype,byte,byte};
chanrevts
=[0]of{mtype,byte,byte};


/*
*{DATA|CHK,res|version,seqno}
*数据队列
*/
chansdata
=[0]of{mtype,byte,byte};
chanrdata
=[0]of{mtype,byte,byte};

/*
*为实现阻塞模拟,需要定义复合类型数组
*/
typedefMsg{
mtypetype;
byteversion;
byteseqno;
};


/*发送记录队列*/
/*当ACK发生的时候,ACK(含)之前的内容都被清除*/
bytehead_seq;
bytetail_seq;
bytecur_seq;
/*
#defineinc(x)(x=(x+1)%WIN)
*/

/*接收方期望系列号*/
byteexpected_seqno;




/*进程说明:
*1.sender2media发送方到接收方的介质模拟进程
*2.receiver2media接收方到发送方的介质模拟进程
*3.sender发送方进程
*4.receiver接收方进程
*/

proctypesender2media()
{
byteseq;
bytev;
mtypetype;

/*阻塞队列*/
Msgmsg[QSIZE];
/*flag语义:
*flag[i]=0的时候,表示msg[i]为空
*flag[i]=m(m>0)的时候,表示从msg[i]被阻塞以来,没有被阻塞的包的个数为m
*flag用法:
*(1)每次收到一个消息,将不为零的flag[i]逐个加一
*(2)发现某个flag[i]的值大于等于QSIZE时必须将其从阻塞队列中取出,进行发送或丢弃,转4
*(3)随机选择一个不为空的阻塞Msg,将其从阻塞队列中取出,进行发送或丢弃
*(4)flag子序列结束
*/
byteflag[QSIZE];
bytei;
/*记录随机数下标用*/
bytej;
/*产生随机数用*/


do
::sdata?type,v,seq->

/*不为空者逐个加一*/
i
=0;
j
=0;
do
::i<QSIZE->
if
::flag[i]!=0->
flag[i]
=flag[i]+1
::else->skip
fi;
i
=i+1
::elsebreak
od;
/*寻找需要立即处理的Msg*/
i
=0;
j
=0;
do
::i<QSIZE->
if
::(flag[i]==QSIZE-1)->
if
::rdata!msg[i].type,msg[i].version,msg[i].seqno->
flag[i]
=0
fi
::else->skip
fi;
i
=i+1;
::elsebreak
od;
/*随机选择一个不为空的阻塞Msg,将其从阻塞队列中取出,进行发送或丢弃*/
i
=0;
j
=0;
do
::i<QSIZE->
if
::flag[i]!=0->
if
::rdata!msg[i].type,msg[i].version,msg[i].seqno->
flag[i]
=0;
::skip
fi
::skip
fi;
i
=i+1
::elsebreak
od;

/*阻塞或传递当前的数据包*/
i
=0;
j
=0;
if
::skip->/*阻塞这个数据包*/
/*随机选择一个空位*/
do
::j>=0->
j
=(j+1)%QSIZE
::skip->
i
=j;/*获得随机数*/
break
od;

if
::flag[i]==0->/*Msg[i]为空,可以放下一条阻塞消息*/
msg[i]
.type=type;
msg[i]
.version=v;
msg[i]
.seqno=seq;
flag[i]
=1;/*标记Msg[i]中已经存有消息*/
gotoendofsend
/*信息已经阻塞,无须发送*/

::else->/*Msg[i]中已有一条消息,且不阻塞这条消息了*/
if
::rdata!type,v,seq
::skip
fi
fi;
endofsend
:skip
::skip->/*直接传递或丢弃数据包*/
if
::rdata!type,v,seq
::skip
fi
fi
od
}


proctypereceiver2media()
{
byteseq;
bytev;
mtypetype;

do
::revts?type,v,seq->
if
::sevts!type,v,seq
::skip
fi
od
}



/*
*发送方
*发送两类消息:DATA(数据)、CHK(缓冲区可用性检查)
*
*接受两类消息:ACK(确认)、RRT(请求重传)
*/
proctypesender()
{

bytes;
byteversion;
byterrt_version;

head_seq
=0;
tail_seq
=0;
cur_seq
=0;

rrt_version
=0;/*initrrtversionnumber*/

do
::(tail_seq+WIN-head_seq+1)%WIN!=QSIZE->/*队列不为满,允许发送*/
if
::sdata!DATA,0,cur_seq/*normalsendaction*/
fi;

progress_2
:cur_seq=(cur_seq+1)%WIN;
tail_seq
=(tail_seq+1)%WIN;;/*更新tail,head保持不变*/



::sevts?ACK,version,s->
/*进行ACK失序处理*/
/*若s不在当前的head_seq~tail_seq范围内,则简单忽略之*/
if
::(head_seq<tail_seq)->/*顺序递增情景*/
if
::(s>tail_seq||s<head_seq)->
gotoendofack
::else
fi
::(head_seq>tail_seq)->/*非递增情景*/
if
::(s<head_seq&&s>tail_seq)->
gotoendofack
::else
fi
::else->/*队列为空*/
gotoendofack
/*此ACK是在介质中被延迟了的ACK,简单丢弃之*/
fi;

assert(s<WIN);
head_seq
=(s+1)%WIN;/*根据ACK更新head_seq,暗含了累积更新*/
cur_seq
=head_seq;

endofack
:skip

::sevts?RRT,version,s->
if
::(version==rrt_version)->/*预期rrt*/
/*将发送链上s(eqno)之前的数据都摘除*/
/*发送链上s之后的所有数据都重发,rrt_version加1*/

head_seq
=s;/*注意:由于是响应RRT消息,不要写成了head_seq=(s+1)%WIN*/
cur_seq
=head_seq;/*调整发送指针,准备重发*/

rrt_version
=(rrt_version+1)%WIN/*inc(rrt_version);*/

::else->/*接受到非预期rrt*/
skip
/*简单丢弃之*/
fi

::((cur_seq!=tail_seq)&&(tail_seq-head_seq)!=0)->
/*队列不为空,允许发送.此情景配合timeout时重发使用*/
/*第一个判断是为了防止发送不存在内容*/
if
::sdata!DATA,0,cur_seq/*normalsendaction*/
fi;
cur_seq
=(cur_seq+1)%WIN;


::timeout->/*超时*/
sdata
!CHK,rrt_version,head_seq;/*超时,发CHK消息,查询是否需要重发*/
od
}



/*
*接收方
*发送两类消息:ACK(确认)、RRT(请求重传)
*
*接受两类消息:DATA(数据)、CHK(缓冲区可用性检查)
*/
proctypereceiver()
{

bytes;
bytev;

do
::rdata?CHK,v,s->/*收到CHK消息*/
if
::(s==expected_seqno)->/*chk检查的数据包即为接收方期望的数据包*/
revts
!RRT,v,s/*直接返回RRT消息*/


::((s<expected_seqno&&expected_seqno-s<WIN/2)||
(s
>expected_seqno&&s-expected_seqno>WIN/2))->/*小于期望包号,ACK之*/
revts
!ACK,0,(expected_seqno+WIN-1)%WIN


::else->/*CHK检查消息错,系统出错*/
printf("s=%dexp=%d ",s,expected_seqno);
assert(false)
fi


::rdata?DATA,v,s->/*收到DATA消息,s为消息序列号*/
/*s与expected_seqno在队列中前后关系的判断:

1.if(s>expected_seqno&&s-expected_seqno<WIN/2)or*normal
(s<expected_seqno&&expected_seqno-s>WIN/2)then
s'>'expected_seqno--收到的消息(s)排在期待数(expected_seqno)的后面

2.if(s<expected_seqno&&expected_seqno-s<WIN/2)or*normal
(s>expected_seqno&&s-expected_seqno>WIN/2)then
s'<'expected_seqno--收到的消息排在期待数的前面

3.if(s==expected_seqno)then
s'=='expected_seqno--收到的消息等于期待的数
*/
if
::((s>expected_seqno&&s-expected_seqno<WIN/2)||
(s
<expected_seqno&&expected_seqno-s>WIN/2))->/*大于*/
/*在存在丢包的流水环境下,这种情况是完全会出现的,不应该看作系统严重错误*/
/*assert(false)*//*非预期消息,系统严重错误*/

/*Yuhuang的方案(2007-7-27):
简单忽略之
*/
skip
::(s==expected_seqno)->/*等于*/
revts
!ACK,0,expected_seqno;
expected_seqno
=(expected_seqno+1)%WIN

::else->/*小于*/
revts
!ACK,0,(expected_seqno+WIN-1)%WIN

fi

od



}


/*Promela入口程序*/
init
{
atomic{
runsender();
runsender2media();
runreceiver();
runreceiver2media();
}

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值