《计算机网络》实验指导书(软件学院2015) - 图文 下载本文

《计算机网络》实验指导书

实验2:可靠数据传输协议的设计与实现

1、实验目的

理解可靠数据传输的基本原理;掌握停等协议的工作原理;在理解停等协议的基础上,理解滑动窗口协议的基本原理;掌握GBN的工作原理;掌握基于UDP设计并实现一个GBN协议的过程与技术。

2、实验环境

? 接入Internet的实验主机; ? Windows xp或Windows 7/8; ? 开发语言:C/C++(或Java)等。

3、实验内容

1) 基于UDP设计一个简单的停等协议;

2) 引入滑动窗口技术,改进停等协议,实现一个简单的GBN协议; 2) 模拟引入数据包的丢失,验证所设计协议的有效性;

3) 改进所设计的GBN协议,支持双向数据传输;(选作内容,加分项目,可以当堂完成或课下完成)

4)将所设计的GBN协议改进为SR协议。(选作内容,加分项目,可以当堂完成或课下完成)

4、实验方式

每位同学上机实验,实验指导教师现场指导。

5、实验要点

1) 深刻理解停等协议与GBN协议的区别;

2) 基于UDP实现的GBN协议,可以不进行差错检测,可以利用UDP协议差错检测;

3) 自行设计数据帧的格式,应至少包含序列号Seq和数据两部分; 4) 自行定义发送端序列号Seq比特数L以及发送窗口大小W,应满足条件W+1<=2L。

5) 一种简单的服务器端计时器的实现办法:设置套接字为非阻塞方式,则服务器端在recvfrom方法上不会阻塞,若正确接收到ACK消息,则计时器清零,若从客户端接收数据长度为-1(表示没有接收到任何数据),则计时器+1,对计

13

《计算机网络》实验指导书

时器进行判断,若其超过阈值,则判断为超时,进行超时重传。(当然,如果服务器选择阻塞模式,可以用到select或epoll的阻塞选择函数,详情见MSDN)

6) 为了模拟ACK丢失,一种简单的实现办法:客户端对接收的数据帧进行计

数,然后对总数进行模N运算,若规定求模运算结果为零则返回ACK,则每接收N个数据帧才返回1个ACK。当N取值大于服务器端的超时阀值时,则会出现服务器端超时现象。

7) 当设置服务器端发送窗口的大小为1时,GBN协议就是停-等协议。

6、参考内容

作为只实现单向数据传输的GBN协议,实质上就是实现为一个C/S应用。

服务器端:使用UDP协议传输数据(比如传输一个文件),等待客户端的请求,接收并处理来自客户端的消息(如数据传输请求),当客户端开始请求数据时进入“伪连接”状态(并不是真正的连接,只是一种类似连接的数据发送的状态),将数据打包成数据报发送,然后等待客户端的ACK信息,同时启动计时器。当收到ACK时,窗口滑动,正常发送下一个数据报,计时器重新计时;若在计时器超时前没有收到ACK,则全部重传窗口内的所以已发送的数据报。

客户端:使用UDP协议向服务器端请求数据,接收服务器端发送的数据报并返回确认信息ACK(注意GBN为累积确认,即若ACK=1和3,表示数据帧2已经正确接收),必须能够模拟ACK丢失直至服务器端超时重传的情况。

(1) 服务器端设计参考 1)命令解析

为了测试客户端与服务器端的通信交互,方便操作,设置了此过程。首先,服务器接收客户端发来的请求数据,

“-time”表示客户端请求获取当前时间,服务器回复当前时间; “-quit”表示客户端退出,服务器回复“Good bye!”;

“-testgbn”表示客户端请求开始测试GBN协议,服务器开始进入GBN传输状态;

其他数据,则服务器直接回复原数据。

2)数据传输数据帧格式定义

在以太网中,数据帧的MTU为1500字节,所以UDP数据报的数据部分应小于1472字节(除去IP头部20字节与UDP头的8字节),为此,定义UDP数据报的数据部分格式为:

Seq为1个字节,取值为0~255,(故序列号最多为256个); Data≤1024个字节,为传输的数据;

14

《计算机网络》实验指导书

最后一个字节放入EOF0,表示结尾。

3)源代码

#include \创建VS项目包含的预编译头文件 #include #include #include #include #pragma comment(lib,\ #define SERVER_PORT 12340 //端口号 #define SERVER_IP \//IP地址 const int BUFFER_LENGTH = 1026; //缓冲区大小,(以太网中UDP的数据帧中包长度应小于1480字节) const int SEND_WIND_SIZE = 10;//发送窗口大小为10,GBN中应满足 W + 1 <= N(W为发送窗口大小,N为序列号个数) //本例取序列号0...19共20个 //如果将窗口大小设为1,则为停-等协议 const int SEQ_SIZE = 20; //序列号的个数,从0~19共计20个 //由于发送数据第一个字节如果值为0,则数据会发送失败 //因此接收端序列号为1~20,与发送端一一对应 BOOL ack[SEQ_SIZE];//收到ack情况,对应0~19的ack int curSeq;//当前数据包的seq int curAck;//当前等待确认的ack int totalSeq;//收到的包的总数 int totalPacket;//需要发送的包总数 //************************************ // Method: getCurTime // FullName: getCurTime // Access: public // Returns: void // Qualifier: 获取当前系统时间,结果存入ptime中 // Parameter: char * ptime //************************************ void getCurTime(char *ptime){ char buffer[128]; memset(buffer,0,sizeof(buffer)); time_t c_time; struct tm *p; time(&c_time);

15

《计算机网络》实验指导书

p = localtime(&c_time); sprintf_s(buffer,\ p->tm_year + 1900, p->tm_mon, p->tm_mday, p->tm_hour, p->tm_min, p->tm_sec); strcpy_s(ptime,sizeof(buffer),buffer); } //************************************ // Method: seqIsAvailable // FullName: seqIsAvailable // Access: public // Returns: bool // Qualifier: 当前序列号 curSeq 是否可用 //************************************ bool seqIsAvailable(){ int step; step = curSeq - curAck; step = step >= 0 ? step : step + SEQ_SIZE; //序列号是否在当前发送窗口之内 if(step >= SEND_WIND_SIZE){ return false; } if(ack[curSeq]){ return true; } return false; } //************************************ // Method: timeoutHandler // FullName: timeoutHandler // Access: public // Returns: void // Qualifier: 超时重传处理函数,滑动窗口内的数据帧都要重传 //************************************ void timeoutHandler(){ printf(\ int index; for(int i = 0;i< SEND_WIND_SIZE;++i){ index = (i + curAck) % SEQ_SIZE;

16