实验报告
实验名称数据链路层协议的理解与实现课程名称计算机网络
姓名王颖学号16008404
日期地点
成绩教师王磊
电气工程学院
东南大学
实验一数据链路层协议的理解与实现
一.实验目的:
1.加深对流量控制、差错处理方法的理解;
2.熟悉TCP/IP编程, 将书本知识运用到实验中;
3.开拓学生的创新意识,培养学生的独立动手操作的能力;
二.实验内容:
1.利用已有的模拟信道程序,编制发送、接收程序的部分模块,使系统具有可靠的收发功能。具体要求
1)采用无连接Socket编程
2)地址与端口
发送端:地址:127.0.0.1 端口:8001
接收端:地址:127.0.0.1 端口:6001
3
4)需考虑的异常情况:出错、丢失、延时
5)采用停等协议
6)单工方式
7)ACK/NAK的表示:ACK:0x06
NAK:0x15
2.待完成模块要求
1)发送程序:偶校验;编码;发送、接收;差错处理、流量控制。
2)接收程序:检查偶校验;应答;发送、接收
三.实验环境(软件、硬件及条件):
Microsoft visual C++ 6.0
四.实验原理
1、程序实现的原理
Windows Sockets(套接字) 是在Windows下一套开放的、支持多种协议的网络编程接口规范。为Windows下网络异步通信提供了一种方便的开发和运行环境。
Windows Sockets规范建立在BSD UNIX 中实现的Berkeley 套接字模型上,现已是TCP/IP网络的标准。它独立于底层的协议。
其原理示意图如下
1)数据链路层
数据链路层目的是建立在物理层基础上,通过一些数据链路层协议,在不太可靠的物理链路上实现可靠的数据传输。即数据链路层提供网络中相邻节点之间可靠的数据通信。
数据链路层的主要功能是为网络层提供连接服务,并在数据链路连接上传送帧。依据功能可以分为有连接和无连接两种。本实验采用的是有应答,无连接服务。
无连接服务时,发送方的数据链路层要发送数据时,就直接发送数据帧。接收方的数据链路层能够接受数据帧,或者收到的帧校验正确,就像源主机数据链路层发送应答帧;不能接受或接受到的帧校验不正确时,就返回否定应答,发送端要么重发原帧,要么进入等待状态。
面向无连接的socket使用方法如下:
3) 停等协议
停止-等待 ARQ协议是指发送端发送一个帧后,不继续发送而是等待对该帧的确认。在发送端,每次只能处理数据链路层的发送缓冲区中的一个数据帧,将缓冲区中的该帧发送出去,同时启动定时器(本实验采用1.5秒),等待接收端会送的确认帧。当发送端收到ACK确认后,认为该帧已成功到达,再取一个新的数据帧进行发送。若收到由接收端发过来的否定确认NAK,则必须暂时保存已发送给的数据帧的备份,进行重传。本实验中,ACK:0x06 NAK:0x15。
本实验的数据在数据链路上传输的情况有四种,即正常、丢失、延时、出错。采用停等协议时如下:
2、程序功能说明,各个模块的详细说明;
3、核心模块程序流程图;
五.实验方法:
1、主要源代码说明;
1.发送方(Sender)程序模块
1)发送信息
int SendMsg(char *msg, int len){
bSending=1;
int n;
n = sizeof(channelsender_addr);
sendto(sender_sockfd, msg, len, 0, (struct sockaddr *) &channelsender_addr, n);
return 0;}
2)接收信息
int ReceiverMsg(char *msg){
int n;
n = sizeof(channelsender_addr);
recvfrom(sender_sockfd,msg,MAX_MSG_SIZE,0,(structsockaddr*)&channelsend
er_addr, &n);
bSending=0;return 0; }
通过设置bSending变量,使用SenderView中的CSenderView::OnTimer (UINT nIDEvent),从而使得数据帧在超时1.5秒后可以重发,如此可以实现延时和出错
情况下的自动重发功能。使用库函数sendto ( SOCKET s, const char FAR * buf, int
len, int flags,const struct sockaddr FAR * to, int tolen )和recvfrom ( SOCKETs, char
FAR* buf, int len, int flags,struct sockaddr FAR* from, int FAR* fromlen );可以实现
3)构成数据帧
产生发送的信息:头、序号、数据、校验位、长度、尾
void Encode(char msg, int no, int len, char *newmsg){
int FLAG;
int count=0;
char temp=msg;
while(temp!=0){
if((temp%2)!=0) count++;
temp=temp/2; }
if(count%2==1) FLAG=1;
else FLAG=0;
*newmsg=HEADER;
*(newmsg+1)=no;
*(newmsg+2)=msg;
*(newmsg+3)=FLAG;
*(newmsg+4)=len;
*(newmsg+5)=HEADER;}
将newmsg数组按数据帧格式赋值,其中头尾均为HEADER(00111100),通过按位取余计算出1的个数,采取奇校验,如果个数为基数,则校验位为1,否则为0.
4)检查应答帧
如果返回的应答帧数据位为ACK,则说明正确发送信息,否则发送出现错误。
BOOL check_data(char *msg){
if(*(msg+1)==ACK) return TRUE;
else return FALSE;}
5)接收从信道发来的信息
LONG CMainFrame::MyChannelSend(UINT wParam,UINT lParam){
char msg[MAX_FRAME_LEN];/* 缓冲区*/
char str_show[100];
//接收信息,写入msg
ReceiverMsg(msg);//接受信息使用库函数ReceiverMsg
//处理信息
if(check_data(msg)==1) //收到正确的应答帧{
if (iSendno iSendno++; //继续发送 Encode(str_send[iSendno], iSendno, msglen, now_send);//产生要发送的信息 SendMsg(now_send, DATA_FRAME_LEN); Show_msg_ListBox("已发送数据:");}} else{ SendMsg(now_send, DATA_FRAME_LEN);//重新发送 Show_msg_ListBox("错误数据:");} 在发送方处理接受的信息时,即处理接受的应答帧时,如果收到正确的应答帧则继续发送,如果应答帧显示发送信息错误,则重新发送。程序根据已经正确接收的帧数(iSendno)和待发送的报文总长度(msglen)的比较,来判断信息是否已经全部正确发送。其中,继续发送时调用Encode函数将要发送的数据构成帧,给信息的序号即是它在字符串中的序号,如此即可保证信息的按序发送,不会出现顺序错误的情况。 2.接收方(Receiver)程序模块