《计算机网络》实验指导书
实验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
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