ARQ协议的实现.docx
《ARQ协议的实现.docx》由会员分享,可在线阅读,更多相关《ARQ协议的实现.docx(25页珍藏版)》请在冰点文库上搜索。
ARQ协议的实现
ARQ协议的实现
一.实验目的
要求学生掌握Socket编程及ARQ协议
2.实验内容
1.必须采用应答机制、超时计数器技术、帧编号技术、重传技术
2.校验和技术可选,
a)校验和s的计算:
设要发送n字节,bi为第i个字,s=(b0+b1+…+bn)mod256
3.在接收端,设置随机数,根据随机数执行相关操作,0代表正常,1代表帧丢失,2代表帧出错,3代表应答帧丢失(即不发生应答帧)
4.使用图形界面,
b)发送端:
显示发送的数据、是否重传、本次帧序号、接收到的应答帧的序号
c)接收端:
显示接收到的数据、本次帧序号、本次随机选择的出错情况、发送应答帧的序号、是否重复
3.实验流程
1.发送端打开窗口,准备发送数据,服务器端启动设备,打开端口,监听各个端口,采用的是多路复用技术,大大缓解了网络阻塞问题
2.服务器端设置随机出错状态
3.客户端点击发送数据(如果发送的数据没有收到应答的帧超过5个,即发送窗口已满,不再发送)
4.正常情况下服务器端会收到数据并发送应答帧,帧或应答帧丢失时或帧出错时丢弃,客户端会启动超时重传,
5.数据发送完毕后关闭
4.关键技术
1.流套接字:
流套接字(SOCK_STREAM):
流套接字用于提供面向连接、可靠的数据传输服务。
该服务将保证数据能够实现无差错、无重复发送,并按顺序接收。
流套接字之所以能够实现可靠的数据服务,原因在于其使用了传输控制协议,即TCP(TheTransmissionControlProtocol)协议。
2.多路复用技术
IntPASCALFARWSAAsyncSelect(SOCKETs,HWNDhWnd,
unsignedintwMsg,longlEvent);
本函数用来请求WindowsSocketsDLL为窗口句柄发一条消息-无论它何时检测到由lEvent参数指明的网络事件.要发送的消息由wMsg参数标明.被通知的套接口由s标识.
3.ARQ协议
选择重传(AutomaticRepeat-reQuest,ARQ)是OSI模型中数据链路层的错误纠正协议之一。
它包括停止等待ARQ协议和连续ARQ协议,错误侦测(ErrorDetection)、正面确认(PositiveAcknowledgment)、逾时重传(RetransmissionafterTimeout)与负面确认继以重传(NegativeAcknowledgmentandRetransmission)等机制。
4.MFC技术
MFC(MicrosoftFoundationClasses),是一个微软公司提供的类库(classlibraries),以C++类的形式封装了Windows的API,并且包含一个应用程序框架,以减少应用程序开发人员的工作量。
其中包含的类包含大量Windows句柄封装类和很多Windows的内建控件和组件的封装类
五.源代码
1.client:
WORDCCClientDlg:
:
CRC(unsignedchar*p,intlen)
{
WORDcrc=0;
unsignedchari;
while(len--)
{
for(i=0x80;i!
=0;i=i>>1)
{
if((crc&0x8000)!
=0)
{
crc=crc<<1;
crc=crc^0x1021;
}
else
{
crc=crc<<1;
}
if((*p&i)!
=0)
{
crc=crc^0x1021;
}
}
p++;
}
returncrc;
}
voidCCClientDlg:
:
OnOk()
{
//TODO:
Addyourcontrolnotificationhandlercodehere
if(judgeFirst)
{
if(ListNum>=5)
{
MessageBox("发送窗口大于5!
");
}
else
{
ret=send(m_hSocket,(char*)buf[NumSend],buf[NumSend][0],0);
ListNum++;
if(ret!
=buf[NumSend][0])
{
TRACE("SendError:
%d\n",WSAGetLastError());
return;
}
pos[timerNum]=0;
m_Timer[timerNum]=SetTimer(timerNum+1,1000,NULL);
timerNum=(timerNum+1)%8;
NumSend=(NumSend+1)%8;
charstr[10];
itoa(NumSend,str,10);
m_Stc_Send=str;
UpdateData(FALSE);
}
}
else
{
MessageBox("请准备好发送帧!
");
}
}
voidCCClientDlg:
:
StartUp()
{
WSADATAwsadata;
WORDversion=MAKEWORD(2,0);
intret=WSAStartup(version,&wsadata);
if(ret!
=0)
{
TRACE("InitializeError!
\n");
}
}
voidCCClientDlg:
:
OnConfig()
{
//TODO:
Addyourcontrolnotificationhandlercodehere
UpdateData(TRUE);
inti=0;
CStringdata[8];
data[0]=m_Data1;
data[1]=m_Data2;
data[2]=m_Data3;
data[3]=m_Data4;
data[4]=m_Data5;
data[5]=m_Data6;
data[6]=m_Data7;
data[7]=m_Data8;
for(i=0;i<8;i++)
{
if(data[i]=="")
{
MessageBox("请讲帧填写完整!
");
return;
}
}
for(i=0;i<8;i++)
{
intstrNum;
unsignedchar*fell;
fell=(unsignedchar*)data[i].GetBuffer(0);
crc=CRC(fell,data[i].GetLength());
strNum=data[i].GetLength();
buf[i]=newunsignedchar[strNum+4];
buf[i][0]=(char)(data[i].GetLength()+4);
for(intj=1;j<=strNum;j++)
buf[i][j]=data[i][j-1];
buf[i][j]=HIBYTE(crc);
buf[i][j+1]=LOBYTE(crc);
buf[i][j+2]=(char)i;
//MessageBox(str);
}
m_Start=0;
m_End=i-1;
UpdateData(FALSE);
if(m_hSocket!
=NULL)
{
closesocket(m_hSocket);
m_hSocket=NULL;
}
if(m_hSocket==NULL)
{
m_hSocket=socket(AF_INET,SOCK_STREAM,0);
ASSERT(m_hSocket!
=NULL);
}
CStringSeverIp;
SeverIp="127.0.0.1";
m_addr.sin_family=AF_INET;
m_addr.sin_port=htons(1314);
m_addr.sin_addr.S_un.S_addr=inet_addr(SeverIp.GetBuffer(0));
ret=connect(m_hSocket,(LPSOCKADDR)&m_addr,sizeof(m_addr));
if(ret==SOCKET_ERROR)
{
TRACE("ConnectError:
%d\n",(error=WSAGetLastError()));
if(error==10061)
AfxMessageBox(_T("连接失败!
"));
return;
}
judgeFirst=1;
m_Stc_Send="0";
UpdateData(FALSE);
WSAAsyncSelect(m_hSocket,AfxGetMainWnd()->m_hWnd,WM_MY_MESSAGE,FD_READ);
this->InitProg();
}
voidCCClientDlg:
:
CleanUp()
{
if(WSACleanup()!
=0)
{
TRACE("UnInitializeError:
%d\n",WSAGetLastError());
}
}
voidCCClientDlg:
:
OnCancel()
{
//TODO:
Addyourcontrolnotificationhandlercodehere
if(m_hSocket!
=NULL)
{
closesocket(m_hSocket);
m_hSocket=NULL;
}
CDialog:
:
OnCancel();
}
voidCCClientDlg:
:
OnDestroy()
{
CDialog:
:
OnDestroy();
//TODO:
Addyourmessagehandlercodehere
CleanUp();
}
voidCCClientDlg:
:
BackStc(intm,inttype)
{
if(!
type)
switch(m)
{
case0:
m_Stc1="重传";
break;
case1:
m_Stc2="重传";
break;
case2:
m_Stc3="重传";
break;
case3:
m_Stc4="重传";
break;
case4:
m_Stc5="重传";
break;
case5:
m_Stc6="重传";
break;
case6:
m_Stc7="重传";
break;
case7:
m_Stc8="重传";
break;
}
else
switch(m)
{
case0:
m_Stc1="不重传";
break;
case1:
m_Stc2="不重传";
break;
case2:
m_Stc3="不重传";
break;
case3:
m_Stc4="不重传";
break;
case4:
m_Stc5="不重传";
break;
case5:
m_Stc6="不重传";
break;
case6:
m_Stc7="不重传";
break;
case7:
m_Stc8="不重传";
break;
}
}
voidCCClientDlg:
:
setProg(intm)
{
switch(m)
{
case0:
m_Prog1.SetPos(pos[m]);
break;
case1:
m_Prog2.SetPos(pos[m]);
break;
case2:
m_Prog3.SetPos(pos[m]);
break;
case3:
m_Prog4.SetPos(pos[m]);
break;
case4:
m_Prog5.SetPos(pos[m]);
break;
case5:
m_Prog6.SetPos(pos[m]);
break;
case6:
m_Prog7.SetPos(pos[m]);
break;
case7:
m_Prog8.SetPos(pos[m]);
break;
}
}
voidCCClientDlg:
:
OnTimer(UINTnIDEvent)
{
//TODO:
Addyourmessagehandlercodehereand/orcalldefault
CDialog:
:
OnTimer(nIDEvent);
intnum;
num=nIDEvent-1;
if(pos[num]>=30)
{
ret=send(m_hSocket,(char*)buf[num],buf[num][0],0);
BackStc(num,0);
UpdateData(FALSE);
pos[num]=0;
if(ret!
=buf[num][0])
{
TRACE("SendError:
%d\n",WSAGetLastError());
return;
}
}
else
{
pos[num]++;
setProg(num);
}
}
voidCCClientDlg:
:
InitProg()
{
m_Prog1.SetRange(0,30);
m_Prog1.SetStep
(1);
m_Prog2.SetRange(0,30);
m_Prog2.SetStep
(1);
m_Prog3.SetRange(0,30);
m_Prog3.SetStep
(1);
m_Prog4.SetRange(0,30);
m_Prog4.SetStep
(1);
m_Prog5.SetRange(0,30);
m_Prog5.SetStep
(1);
m_Prog6.SetRange(0,30);
m_Prog6.SetStep
(1);
m_Prog7.SetRange(0,30);
m_Prog7.SetStep
(1);
m_Prog8.SetRange(0,30);
m_Prog8.SetStep
(1);
}
LRESULTCCClientDlg:
:
OnMyMessage(WPARAMwParam,LPARAMlParam)
{
intcm;
if(WSAGETSELECTERROR(lParam))
{
closesocket(wParam);
return0;
}
if(WSAGETSELECTEVENT(lParam)==FD_READ)
{
charnum;
ret=recv(m_hSocket,&num,1,0);
if(ret==0||ret==SOCKET_ERROR)
{
TRACE("Recvdataerror:
%d\n",WSAGetLastError());
return0;
}
cm=num-1;
KillTimer(m_Timer[cm]);
ListNum--;
BackStc(cm,1);
charstr[10];
itoa(cm+1,str,10);
m_Stc_RECV=str;
UpdateData(FALSE);
}
return0;
}
intCCClientDlg:
:
OnCreate(LPCREATESTRUCTlpCreateStruct)
{
if(CDialog:
:
OnCreate(lpCreateStruct)==-1)
return-1;
//TODO:
Addyourspecializedcreationcodehere
return0;
}
2.server:
voidCCServerDlg:
:
OnOk()
{
//TODO:
Addyourcontrolnotificationhandlercodehere
CStringError[4]={"正常","出错","帧丢失","应答帧丢失"};
srand((unsigned)time(NULL));
m_StcE0=Error[ENum[0]=rand()%4];
m_StcE1=Error[ENum[1]=rand()%4];
m_StcE2=Error[ENum[2]=rand()%4];
m_StcE3=Error[ENum[3]=rand()%4];
m_StcE4=Error[ENum[4]=rand()%4];
m_StcE5=Error[ENum[5]=rand()%4];
m_StcE6=Error[ENum[6]=rand()%4];
m_StcE7=Error[ENum[7]=rand()%4];
UpdateData(FALSE);
}
voidCCServerDlg:
:
OnSetserver()
{
//TODO:
Addyourcontrolnotificationhandlercodehere
if(m_hSocket!
=NULL)
{
closesocket(m_hSocket);
m_hSocket=NULL;
}
if(m_hSocket==NULL)
{
m_hSocket=socket(AF_INET,SOCK_STREAM,0);
ASSERT(m_hSocket!
=NULL);
}
m_addr.sin_family=AF_INET;
m_addr.sin_addr.S_un.S_addr=INADDR_ANY;
m_addr.sin_port=htons(1314);
ret=bind(m_hSocket,(LPSOCKADDR)&m_addr,sizeof(m_addr));
if(ret==SOCKET_ERROR)
{
TRACE("BindEoor:
%d\n",(error=WSAGetLastError()));
return;
}
AfxMessageBox("服务器开始启动");
WSAAsyncSelect(m_hSocket,AfxGetMainWnd()->m_hWnd,WM_MY_MESSAGE,FD_ACCEPT);
ret=listen(m_hSocket,5);
if(ret==SOCKET_ERROR)
{
TRACE("ListenError:
%d\n",(error=WSAGetLastError()));
return;
}
}
voidCCServerDlg:
:
StartUp()
{
WSADATAwsaData;
WORDversion=MAKEWORD(2,0);
intret=WSAStartup(version,&wsaData);
if(ret!
=0)
TRACE("InitializeError!
\n");
}
voidCCServerDlg:
:
CleanUp()
{
if(WSACleanup()!
=0)
{
TRACE("UnInitializeerror:
%d\n",WSAGetLastError());
}
}
voidCCServerDlg:
:
SetEdit(char*str,intm)
{
switch(m)
{
case0:
if(ENum[0]==0||ENum[0]==3)
{
if(m_Data0==str)
m_StcR0="重复";
m_Data0=str;
}
break;
case1:
if(ENum[1]==0||ENum[1]==3)
{
if(m_Data1==str)
m_StcR1="重复";
m_Data1=str;
}
break;
case2:
if(ENum[2]==0||ENum[2]==3)
{
if(m_Data2==str)
m_StcR2="重复";
m_Data2=str;
}
break;
case3:
if(ENum[3]==0||ENum[3]==3)
{
if(m_Data3==str)
m_StcR3="重复";
m_Data3=str;
}
break;
case4:
if(ENum[4]==0||ENum[4]==3)
{
if(m_Data4==str)
m_StcR4="重复";
m_Data4=str;
}
break;
case5:
if(ENum[5]==0||ENum[5]==3)
{
if(m_Data5==str)
m_StcR5="重复";
m_Data5=str;
}
break;
case6:
if(ENum[6]==0||ENum[6]==3)
{
if(m_Data6==str)
m_StcR6="重复";
m_Data6=str;
}
break;
case7:
if(ENum[7]==0||ENum[7]==3)
{
if(m_Data7==str)
m_StcR7="重复";
m_Data7=str;
}
break;
}
UpdateData(FALSE);