数据链路层协议的设计与实现Word格式.docx
《数据链路层协议的设计与实现Word格式.docx》由会员分享,可在线阅读,更多相关《数据链路层协议的设计与实现Word格式.docx(14页珍藏版)》请在冰豆网上搜索。
四、实验过程
1、程序功能及设计思路
功能概述:
用客户端/服务器模式代表A站、B站。
先由客户端输入服务器IP地址,发送SYN同步帧,告诉服务器准备接受。
客户端输入数据后,会进行CRC编码,再发送数据帧;
服务器收到后,先进行校验,数据正确则发送ACK帧,客户端则发送下一帧数据;
否则服务器发送NAK帧,客户端重新发送该数据。
CRC校验:
1)将收到的字符转为int型(32位),并将其二进制码左移16位,存于data;
2)进行C(D)=Remainder[(S(D)∙D^L)/g(D)],即CRC校验,得到校验位。
3)将校验位加在信息元后,组成24位的码字,存于要发送的数据帧dframe。
停等式ARQ协议:
Client:
1)置SN=0;
2)收到数据,将SN分配给该数据,如果没有收到,则等待;
3)存于要发送的数据帧中,发送给server;
4)如果从server收到确认帧,且RN>
SN,则SN加1(模2),返回2;
如果收到NAK或RN=SN,则返回3,重传数据。
Server:
1)置RN=0;
2)从client收到一个SN=RN的帧,进行CRC校验检查,无错后输出,并置RN加1、发送ACK帧;
否则发送NAK帧,请求重发。
2、C语言程序代码:
客户端Client:
//***********************client.c*****************************
#include<
winsock.h>
//WINSOCKAPI的头文件,需要包含在项目中
#pragmacomment(lib,"
ws2_32.lib"
)//WINSOCKAPI连接库文件
stdio.h>
string.h>
interr;
SOCKETsock;
//用于服务器监听的Socket
SOCKADDR_INaddrSrv;
//服务端地址
unsignedcharsendBuf[100];
//发送缓存
charserverIp[20];
//客户端ip地址
intsocklen=sizeof(SOCKADDR_IN);
//Socket的地址值的长度
intcf_len=sizeof(structsockaddr);
structdataFrame//数据帧
{
intseq;
//分段消息的序号
intSN;
//发送序号
unsignedintdata[100];
intmsglen;
//字符长度,采用长度计数的组帧技术
};
structconFrame//控制帧
intRN;
//接收序号
chartype[3];
//表明帧的类型:
SYN同步、EOT送毕、ACK确认应答、NCK否定应答
structdataFramedframe;
structconFramecframe;
//************************初始化******************************
voidinitialization()
{
WORDwVersionRequested;
WSADATAwsaData;
wVersionRequested=MAKEWORD(1,1);
//WinSocket1.1版本
err=WSAStartup(wVersionRequested,&
wsaData);
//wsaData用来存储系统传回的关于WinSocket的资料
if(LOBYTE(wsaData.wVersion)!
=1||HIBYTE(wsaData.wVersion)!
=1){
WSACleanup();
}
return;
}
//************************计算CRC-16******************************
//基于32位系统,int型长度为4字节,CRC-16的生成多项式为g(D)=D^16+D^15+D^2+1
voidcaculate_crc16(unsignedchar*msg,intlenth,unsignedint*crc)
unsignedintdata=0;
inti,j;
//chars[32];
//用于测试时显示二进制码
for(i=0;
i<
lenth;
i++,crc++,msg++){
data=(int)*msg;
//itoa(data,s,2);
//把整数转为二进制码
//printf("
第%d字的二进制码:
%s\n"
i+1,s);
//test
*crc=data<
<
16;
for(j=0;
j<
j++)
{
if((data&
0x8000))
{
data=(data<
1)&
0xffff;
data=data^0x8005;
}
elsedata=(data<
}
*crc=*crc|data;
//把校验位放在信息元后面,存在一个int变量中
//itoa(*crc,s,2);
加上CRC校验位后的二进制码:
s);
}
//************************发送数据帧******************************
voidSendFrame(){
//建立socket,SOCK_DGRAM为使用不连续不可靠的数据包连接
sock=socket(AF_INET,SOCK_DGRAM,0);
if(sock==-1){
printf("
Buildingasocketfailed.\n"
);
return;
printf("
inputserver'
sIP:
"
scanf("
%s"
serverIp);
//输入服务器ip
addrSrv.sin_addr.S_un.S_addr=inet_addr(serverIp);
//设置服务器地址
addrSrv.sin_family=AF_INET;
addrSrv.sin_port=htons(6000);
//设置服务器端口号
strcpy(cframe.type,"
SYN"
cframe.RN=0;
//发送同步消息
sendto(sock,(char*)&
cframe,sizeof(cframe)+1,0,(SOCKADDR*)&
addrSrv,socklen);
----------------------------------------------\n"
dframe.seq=0;
while
(1)
{
memset(sendBuf,0,sizeof(sendBuf));
//清空缓冲区
Inputthemessage:
//输入message,若输入exit则停止发送
scanf("
sendBuf);
if(strcmp(sendBuf,"
exit"
)==0){
//当客户端要断开连接时,给服务器发送EOT送毕控制帧
EOT"
//发送EOT消息
cframe,sizeof(cframe)+1,0,(SOCKADDR*)&
printf("
------------------closesocket!
-----------------\n"
break;
dframe.seq++;
dframe.SN=dframe.seq%2;
dframe.msglen=strlen(sendBuf);
caculate_crc16(sendBuf,dframe.msglen,dframe.data);
//发送消息
sendto(sock,(char*)&
dframe,sizeof(structdataFrame),0,(SOCKADDR*)&
while
(1)
{
recvfrom(sock,(char*)&
cframe,sizeof(structconFrame),0,(SOCKADDR*)&
addrSrv,&
cf_len);
//接受来自服务器的应答帧
if(strcmp(cframe.type,"
ACK"
)==0)//如果收到ACK应答指令,则发送下一个message
if(cframe.RN!
=dframe.SN){
printf("
--------messageisdeliveredsuccessfully.----------\n"
break;
}
}elseif((strcmp(cframe.type,"
NAK"
)==0)|(cframe.RN==dframe.SN))
printf("
--------messageredeliverring.----------\n"
sendto(sock,(char*)&
//重发该消息
}
closesocket(sock);
//关闭连接
voidmain(){
initialization();
//初始化阶段,若返回值err=0,则表示初始化成功
if(err){
Initializationfalied.\n"
exit(0);
SendFrame();
WSACleanup();
//**********************endofprogram************************
服务器Server:
//***********************