ARQ协议的实现
五.源代码
1.client:
WORD CCClientDlg::CRC(unsigned char *p,int len)
{
WORD crc=0;
unsigned char i;
while(len--)
{
for(i=0x80;i!=0;i=i>>1)
{
if((crc&0x8000)!=0)
{
crc=crc<<1;
UpdateData(FALSE);
WSAAsyncSelect(m_hSocket,AfxGetMainWnd()->m_hWnd,WM_MY_MESSAGE,FD_READ);
this->InitProg();
}
void CCClientDlg::CleanUp()
{
if(WSACleanup()!=0)
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));
break;
case 7:
m_Stc8="不重传";
break;
}
}
void CCClientDlg::setProg(int m)
{
switch(m)
{
case 0:
m_Prog1.SetPos(pos[m]);
break;
case 1:
m_Prog2.SetPos(pos[m]);
break;
case 2:
{
TRACE("Send Error:%d\n",WSAGetLastError());
return;
}
}
else
{
pos[num]++;
setProg(num);
}
}
void CCClientDlg::InitProg()
{
m_Prog1.SetRange(0,30);
{
closesocket(m_hSocket);
m_hSocket=NULL;
}
CDialog::OnCancel();
}
void CCClientDlg::OnDestroy()
{
CDialog::OnDestroy();
// TODO: Add your message handler code here
break;
case 7:
m_Prog8.SetPos(pos[m]);
break;
}
}
void CCClientDlg::OnTimer(UINT nIDEvent)
{
// TODO: Add your message handler code here and/or call default
CDialog::OnTimer(nIDEvent);
int ret=WSAStartup(version,&wsadata);
if(ret!=0)
{
TRACE("Initialize Error!\n");
}
}
void CCClientDlg::OnConfig()
{
// TODO: Add your control notification handler code here
crc=crc^0x1021;
}
else
{
crc=crc<<1;
}
if((*p&i)!=0)
{
crc=crc^0x1021;
}
}
p++;
}
return crc;
}
void CCClientDlg::OnOk()
{
// TODO: Add your control notification handler code here
{
TRACE("UnInitialize Error:%d\n",WSAGetLastError());
}
}
void CCClientDlg::OnCancel()
{
// TODO: Add your control notification handler code here
if(m_hSocket!=NULL)
m_Stc4="重传";
break;
case 4:
m_Stc5="重传";
break;
case 5:
m_Stc6="重传";
break;
case 6:
m_Stc7="重传";
break;
case 7:
m_Stc8="重传";
break;
}
else
switch(m)
{
case 0:
m_Stc1="不重传";
4.使用图形界面,
发送端:显示发送的数据、是否重传、本次帧序号、接收到的应答帧的序号
接收端:显示接收到的数据、本次帧序号、本次随机选择的出错情况、发送应答帧的序号、是否重复
实验流程
1.发送端打开窗口,准备发送数据,服务器端启动设备,打开端口,监听各个端口,采用的是多路复用技术,大大缓解了网络阻塞问题
int num;
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])
ARQ协议的实现
一.实验目的
要求学生掌握Socket编程及ARQ协议
实验内容
1.必须采用应答机制、超时计数器技术、帧编号技术、重传技术
2.校验和技术可选,
校验和s的计算:设要发送n字节,bi为第i个字,s=(b0+b1+…+bn) mod 256
3.在接收端,设置随机数,根据随机数执行相关操作,0代表正常,1代表帧丢失,2代表帧出错,3代表应答帧丢失(即不发生应答帧)
if(ret==SOCKET_ERROR)
{
TRACE("Connect Error:%d\n",(error=WSAGetLastError()));
if(error==10061)
AfxMessageBox(_T("连接失败!"));
return;
}
judgeFirst=1;
m_Stc_Send="0";
crc=CRC(fell,data[i].GetLength());
strNum=data[i].GetLength();
buf[i]=new unsigned char[strNum+4];
buf[i][0]=(char)(data[i].GetLength()+4);
for(int j=1;j<=strNum;j++)
UpdateData(TRUE);
int i=0;
CString data[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;
brea源自文库;
case 1:
m_Stc2="不重传";
break;
case 2:
m_Stc3="不重传";
break;
case 3:
m_Stc4="不重传";
break;
case 4:
m_Stc5="不重传";
break;
case 5:
m_Stc6="不重传";
break;
case 6:
m_Stc7="不重传";
m_Prog3.SetPos(pos[m]);
break;
case 3:
m_Prog4.SetPos(pos[m]);
break;
case 4:
m_Prog5.SetPos(pos[m]);
break;
case 5:
m_Prog6.SetPos(pos[m]);
break;
case 6:
m_Prog7.SetPos(pos[m]);
ARQ协议
选择重传(Automatic Repeat-reQuest,ARQ)是OSI模型中数据链路层的错误纠正协议之一。它包括停止等待ARQ协议和连续ARQ协议,错误侦测(Error Detection)、正面确认(Positive Acknowledgment)、逾时重传(Retransmission after Timeout)与负面确认继以重传(Negative Acknowledgment and Retransmission)等机制。
2.服务器端设置随机出错状态
3.客户端点击发送数据(如果发送的数据没有收到应答的帧超过5个,即发送窗口已满,不再发送)
4.正常情况下服务器端会收到数据并发送应答帧,帧或应答帧丢失时或帧出错时丢弃,客户端会启动超时重传,
5.数据发送完毕后关闭
关键技术
1.流套接字:
流套接字(SOCK_STREAM):
流套接字用于提供面向连接、可靠的数据传输服务。该服务将保证数据能够实现无差错、无重复发送,并按顺序接收。流套接字之所以能够实现可靠的数据服务,原因在于其使用了传输控制协议,即TCP(The Transmission Control Protocol)协议。
{
TRACE("Send Error:%d\n",WSAGetLastError());
return;
}
pos[timerNum]=0;
m_Timer[timerNum]=SetTimer(timerNum+1,1000,NULL);
timerNum=(timerNum+1)%8;
NumSend=(NumSend+1)%8;
{
closesocket(m_hSocket);
m_hSocket=NULL;
}
if(m_hSocket==NULL)
{
m_hSocket=socket(AF_INET,SOCK_STREAM,0);
ASSERT(m_hSocket!=NULL);
}
CString SeverIp;
SeverIp="127.0.0.1";
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])
data[7]=m_Data8;
for(i=0;i<8;i++)
{
if(data[i]=="")
{
MessageBox("请讲帧填写完整!");
return;
}
}
for(i=0;i<8;i++)
{
int strNum;
unsigned char *fell;
fell=(unsigned char *)data[i].GetBuffer(0);
CleanUp();
}
void CCClientDlg::BackStc(int m,int type)
{
if(!type)
switch(m)
{
case 0:
m_Stc1="重传";
break;
case 1:
m_Stc2="重传";
break;
case 2:
m_Stc3="重传";
break;
case 3:
MFC技术
MFC(Microsoft Foundation Classes),是一个微软公司提供的类库(class libraries),以C++类的形式封装了Windows的API,并且包含一个应用程序框架,以减少应用程序开发人员的工作量。其中包含的类包含大量Windows句柄封装类和很多Windows的内建控件和组件的封装类
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)
char str[10];
itoa(NumSend,str,10);
m_Stc_Send=str;
UpdateData(FALSE);
}
}
else
{
MessageBox("请准备好发送帧!");
}
}
void CCClientDlg::StartUp()
{
WSADATA wsadata;
WORD version=MAKEWORD(2,0);
多路复用技术
Int PASCAL FAR WSAAsyncSelect (SOCKET s,HWND hWnd,
unsigned int wMsg,long lEvent);
本函数用来请求Windows Sockets DLL为窗口句柄发一条消息-无论它何时检测到由lEvent参数指明的网络事件.要发送的消息由wMsg参数标明.被通知的套接口由s标识.