qwertyuiopasdfghjklzxcvbnmqwerty uiopasdfghjklzxcvbnmqwertyuiopasd fghjklzxcvbnmqwertyuiopasdfghjklzx cvbnmqwertyuiopasdfghjklzxcvbnmq wertyuiopasdfghjklzxcvbnmqwertyui opasdfghjklzxcvbnmqwertyuiopasdfg 计算机网络实习报告 hjklzxcvbnmqwertyuiopasdfghjklzxcv ---- 用 NS2 实现 RDT3.0 协议 bnmqwertyuiopasdfghjklzxcvbnmqw ertyuiopasdfghjklzxcvbnmqwertyuio pasdfghjklzxcvbnmqwertyuiopasdfgh klzxcvbnmqwertyuiopasdfghjklzxcvb nmqwertyuiopasdfghjklzxcvbnmqwe 报告者 : 吴昊 051221100 rtyuiopasdfghjklzxcvbnmqwertyuiop 朱妍姝 051221152 asdfghjklzxcvbnmqwertyuiopasdfghj 宋丹 051221079 黄旻倩 051070018 klzxcvbnmrtyuiopasdfghjklzxcvbnmq wertyuiopasdfghjklzxcvbnmqwertyui 2007 年 12 月 19 日星期三 opasdfghjklzxcvbnmqwertyuiopasdfg hjklzxcvbnmqwertyuiopasdfghjklzxcv
一 差错控制 & 流量控制的基本概念 1. 差错控制 : 用于检测和纠正分组在传输过程中出现的差错的机制 不可靠的网络传输, 产生的差错有三种 : 分组中比特的翻转 分组丢失 分组延迟或失序到达 传输层要为应用层实现相对可靠的传输, 取决于应用层对传输层的需求 常用的差 错检测技术有 : 差错检测 : 分组中产生比特位差错时, 接收者能够检测到这些差错 肯定确认 : 接收者为成功接收到的 没有差错的帧返回一个肯定的确认 超时后重传 : 在预定时间里没有收到确认的情况下, 发送者会重新传输一个帧 否认与重传 : 接收者为检测到差错的帧返回一个否认, 发送者受到这个否认 后, 重新传输这些帧 以上的这些机制都被称为自动重传请求 (automatic repeat request,arq) 2. 流量控制 : 用于确保发送实体发送的数据不会超出接收实体接受数据能力的一种 技术 如果没有流量控制, 接受着会产生缓冲溢出, 所以应当由某种方法能够限制 发送者发送数据 二 RDT3.0 简介 一个可靠的传输层基本模型如图 1 所示 : 2
图 1 传输层与应用层的基本模式图 RDT3.0: 在不可靠网络上提供可靠的传输 基本假设 : 基于一个会瘫痪的链路, 并且传输的分组会丢失 ( 无论是数据分组还是确认 分组 ) 其总体结构如下图所示 : 图 2 RDT3.0 的总体结构图 基本思想 : 使用停止等待流量控制和停止等待 ARQ 发送方发送一个数据分组后, 必须等待一个确认 受到确认后, 发送方才能发送下 一个确认 具体做法如下 : 3
数据分组和确认都被标记上 0 和 1, 用来判别重复 接收着接收到被标记为 i 的数 据分组, 返回被标记为 i 的 ACK 发送者发送一个数据分组 i, 等待一个合理的时间 若在这段时间里没有收到 ACKi ( 确认 i), 则重传这个分组 如果收到了 ACKi 则发送下一分组, 且将计时器置位 接收者如果受到分组 i, 接收方就会返回 ACKi 以确认收到的分组 工作过程如图 : 图 3 RDT3.0 的工作过程图 基本工作流程图如下 : 4
图 4 RDT3.0 的基本工作流程图 三 实验内容 在传输层上实现一个 RDT3.0 协议, 包括发送与接受数据 GBN 差错控制与流量控制 并且用两三个节点来演示所做的协议 四 实现思想 主要采用的是固定的滑动窗口与 GBN 差错控制 其思想描述如下 : 接收方和发送方都维护一个窗口, 大小为 N 5
发送方的处理情况 : 允许在没有收到确认的情况下发送 N 个数据分组, 若发送了 N 个 没有收到确认的分组后, 就必须等待确认到达 收到 ACKi 表示, 序号 i 之前的分组都已经 收到 受到 REJi 表示序号 i 以及 i 之后的分组都必须重传 接受方的处理情况 : 收到数据分组 i, 若是按序到达的分组则接受 若不是按序到达的 分组, 则丢弃受到的分组且发送 REJj 表示期望受到的分组是序号为 j 的分组 在一定时候 发送 ACK 发送方和接收方维护的窗口如下图所示 : 图 5 发送方和接收方维护的窗口描述图 拥塞控制和流量控制 : 当检测到有分组被丢弃时, 自动减小发送速率 五 代码部分 在理解 RDT 协议的主要内容后, 我们要做的就是用 C++ 与 Tcl 语言实现它 首先为 RDT 定义自己的首部 : 6
struct hdr_rdt { int ack; // is it ack packet? int rej; // is it rej packet? int seq; // rdt sequence number int nbytes; // bytes for rdt pkt double time; // current time int scale; // scale (0-4) associated with data rates // Packet header access functions static int offset_; inline static int& offset() { return offset_; } inline static hdr_rdt* access(const Packet* p) { return (hdr_rdt*) p->access(offset_); } }; 为发送方和接收方设置定时器 : // Sender uses this timer to schedule next app data packet transmission time class SendTimer : public TimerHandler { public: SendTimer(rdtApp* t) : TimerHandler(), t_(t) {} inline virtual void expire(event*); protected: rdtapp* t_; }; // Reciver uses this timer to schedule next ack packet transmission time class AckTimer : public TimerHandler { public: AckTimer(rdtApp* t) : TimerHandler(), t_(t) {} inline virtual void expire(event*); protected: rdtapp* t_; }; 然后按发送方和接收方行为分别定义函数 : void send_rdt_pkt(); // called by SendTimer:expire (Sender) void send_ack_pkt(); // called by AckTimer:expire (Receiver) void send_rej_pkt(); // called by Receiver when packets not in order void resend_rdt_pkt(const hdr_rdt *mh_buf); // called by sender to resend rdt_pkts void adjust_rwindow(); //receiver adjusts its window after receive a rdt_pkt or send a ack_pkt void adjust_swindow(const hdr_rdt *mh_buf); //sender adjusts its window after receive a rdt_pkt or send a ack_pkt 接收分组的处理函数如下 : 7
// Receive message from underlying agent void rdtapp::recv_msg(int nbytes, const char *msg) { if(msg) { hdr_rdt* mh_buf = (hdr_rdt*) msg; if(mh_buf->ack == 1) { // 收到 ACK 分组 adjust_swindow(mh_buf); // 调整发送窗口大小 lastack_ = mh_buf->seq; // 记录最后收到的 ACK 序号 set_scale(mh_buf); // 调整发送速率 } else if( mh_buf ->rej == 1) { // 收到 REJ 分组 resend_rdt_pkt(mh_buf); // 重新发送 REJ 分组 } else { // 收到的是 rdt 的数据分组 account_recv_pkt(mh_buf); if(mh_buf->seq == 8) send_ack_pkt(); // 等于八, 表示是握手, 发送 ACK, 建立连接 else if(mh_buf->seq!=((rseq_ + 1) % 8)) {// 收到的包顺序错误, 发送 REJ 分组 send_rej_pkt(); } else { rseq_= mh_buf ->seq; // 收到按序到达的包, 调整接收窗口大小 rwindow_--; } } } 相应地, 为 RDT Application Class 定义一些私有变量 : int rwindow_; //the size of receiver s window int swindow_; // the size of sender s window int lastack_; //the seq of the last ack_pkt int rseq_; //the seq of the last rdt_pkt sent by sender int sseq_; // the seq of the last rdt_pkt received by receiver SendTimer snd_timer_; // SendTimer AckTimer ack_timer_; // AckTimer 程序的其它部分见源程序 rdt.h, rdt.cc, rdt-app,h, rdt-app.cc 协议写好, 并修改 packet.h,ns-packet.tcl,agent.h, app.h,ns-default.tcl 等文件后, 执行 make 命令重新编译 NS, 将协议添加进去 至此就可以用一个 tcl 程序来演示我们添加的 RDT 协议啦 六 程序截图 8
9