TCP Reno成员函数的解释(中文)好东西大家分享
2011-01-06 16:38
225 查看
/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
/*
* Copyright (c) 1990, 1997 Regents of the University of California.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by the University of California, Lawrence Berkeley Laboratory,
* Berkeley, CA. The name of the University may not be used to
* endorse or promote products derived from this software without
* specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
#ifndef lint
static const char rcsid[] =
"@(#) $Header: /nfs/jade/vint/CVSROOT/ns-2/tcp/tcp-reno.cc,v 1.42 2005/07/13 03:51:32 tomh Exp $ (LBL)";
#endif
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include "ip.h"
#include "tcp.h"
#include "flags.h"
static class RenoTcpClass : public TclClass {
public:
RenoTcpClass() : TclClass("Agent/TCP/Reno") {}
TclObject* create(int, const char*const*) {
return (new RenoTcpAgent());
}
} class_reno;
int RenoTcpAgent::window()
{
//
// reno: inflate the window by dupwnd_
// dupwnd_ will be non-zero during fast recovery,
// at which time it contains the number of dup acks
//
int win = int(cwnd_) + dupwnd_; //在快速恢复时,增加发送窗口,dupwnd_=0(初始)或者=numdupacks_,在dupack_>numdupacks_时,dupwnd_每次还要+1
if (frto_ == 2) {
// First ack after RTO has arrived.
// Open window to allow two new segments out with F-RTO.
win = force_wnd(2);
}
if (win > int(wnd_))
win = int(wnd_);
return (win);
}
double RenoTcpAgent::windowd()
{
//
// reno: inflate the window by dupwnd_
// dupwnd_ will be non-zero during fast recovery,
// at which time it contains the number of dup acks
//
double win = cwnd_ + dupwnd_;
if (win > wnd_)
win = wnd_;
return (win);
}
RenoTcpAgent::RenoTcpAgent() : TcpAgent(), dupwnd_(0)
{
}
void RenoTcpAgent::recv(Packet *pkt, Handler*)
{
hdr_tcp *tcph = hdr_tcp::access(pkt);
int valid_ack = 0;
if (qs_approved_ == 1 && tcph->seqno() > last_ack_)
endQuickStart();
if (qs_requested_ == 1)
processQuickStart(pkt);
#ifdef notdef
if (pkt->type_ != PT_ACK) {
fprintf(stderr,
"ns: confiuration error: tcp received non-ack/n");
exit(1);
}
#endif
/* W.N.: check if this is from a previous incarnation */
if (tcph->ts() < lastreset_) {
// Remove packet and do nothing
Packet::free(pkt);
return;
}
++nackpack_;
ts_peer_ = tcph->ts();
if (hdr_flags::access(pkt)->ecnecho() && ecn_)
ecn(tcph->seqno());
recv_helper(pkt);
recv_frto_helper(pkt);
if (tcph->seqno() > last_ack_) { //本ACK序号>上次记录的ACK序号,表示是新的ACK
if (last_cwnd_action_ == CWND_ACTION_DUPACK) //*本次新ACK,则退出快速重传
last_cwnd_action_ = CWND_ACTION_EXITED; //*
dupwnd_ = 0; //*设置dupwnd_=0,用于下次计算发送窗口win
recv_newack_helper(pkt);
if (last_ack_ == 0 && delay_growth_) { //是连接以来的第一个ACK
cwnd_ = initial_window(); //初始化CWND
}
} else if (tcph->seqno() == last_ack_) { // 本次不是新ACK,是上次的重复ACK
if (hdr_flags::access(pkt)->eln_ && eln_) {
tcp_eln(pkt);
return;
}
//以下是重复数ACK=1-2、3和3以上的三种情况的处理
if (++dupacks_ == numdupacks_) { //*默认numdupacks_=3,有3个重传就执行快速恢复和快速重传
dupack_action(); //改变SSTHRESH、CWND,并重设定时器超时
if (!exitFastRetrans_) //*exitFastRetrans_默认为1,reno专用
dupwnd_ = numdupacks_;
} else if (dupacks_ > numdupacks_ && (!exitFastRetrans_ //*超过numdupacks_次重传ACK,且上次也是重传ACK
|| last_cwnd_action_ == CWND_ACTION_DUPACK )) {
++dupwnd_; //* 执行快速恢复:在超过numdupacks_次重传ACK后,每次再收到一个重复ACK,使发送窗口+1,加快发送,fast recovery
} else if (dupacks_ < numdupacks_ && singledup_ ) { //如果是1次到2次重复ACK,发送一个新分组 ,这是限制传输机制
send_one();
}
}
if (tcph->seqno() >= last_ack_) //本ACK序号>=上次ACK,表示是新ACK或重复ACK,是合法的
// Check if ACK is valid. Suggestion by Mark Allman.
valid_ack = 1;
Packet::free(pkt); //合法,回收该分组内存
#ifdef notyet
if (trace_)
plot();
#endif
/*
* Try to send more data
*/
if (valid_ack || aggressive_maxburst_) //aggressive_maxburst_默认值为1
if (dupacks_ == 0 || dupacks_ > numdupacks_ - 1) //*如果是新的ACK或者重复ACK数>=3,尽量发送更多的数据
send_much(0, 0, maxburst_); //即如果重复ACK=1或者2,则不这样传,而按照上面只发送一个分组
}
/*注: 限制传输机制(Limited Transmit mechanism)
我们知道,当前的TCP应用主要有两种重传机制-快速重传和超时重传。当TCP源端收到3个ACK副本时,
就会触发快速重传机制,此时源端重传丢失的数据包并且将拥塞窗口大小减半。这种情况下,TCP流往往能
够很快从丢包中恢复过来,重新回到原先的发送速率。但如果TCP源端没有收到3个ACK副本,例如拥塞窗口
大小小于4,那么TCP源端则需要等待相当长时间,以便超时重发。这样,小窗口的TCP流就很容易陷入不必
要的超时重发,使其吞吐量大大下降。
为了避免这种不必要的超时重传,一种改进办法就是只要TCP源端收到一个或者两个ACK副本,并且如果
通告窗口允许,便继续发送新的数据包。这是因为只要收到ACK副本,就表明有数据包已经离开网络被接受
端接收了,而此时源端还无法判断数据包是否被丢弃,根据“数据包守恒”原则,只要遵守拥塞窗口的规范,
也即同时在网络中传送的数据包数量不能超过拥塞窗口的大小(以数据包为单位),源端就可以继续发送新
的数据包
4000
。这种机制称为限制传输机制(Limited Transmit mechanism),这种机制对排序的数据包尤其有效。
限制传输机制可以使小窗口的TCP流很快从丢包中恢复过来。例如,对于拥塞窗口大小为4地TCP流,如果
其第二个数据包丢失,那么按传统地做法需要等待超时重传。而在限制传输机制下,当源端收到对第三个数据
包确认的ACK副本时(ACK中要求源端发送第二个数据包),继续发送新的数据包,最终源端可以收到三个ACK
副本从而触发快速重传,从而减少了不必要的超时重传。
*/
//last_cwnd_action_即上次对CWND的动作为DUPACK,则本次允许快速重传 //本次
int
RenoTcpAgent::allow_fast_retransmit(int last_cwnd_action_)
{
return (last_cwnd_action_ == CWND_ACTION_DUPACK);
}
/*
* Dupack-action: what to do on a DUP ACK. After the initial check
* of 'recover' below, this function implements the following truth
* table:
*
* bugfix ecn last-cwnd == ecn action
*
* 0 0 0 reno_action
* 0 0 1 reno_action [impossible]
* 0 1 0 reno_action
* 0 1 1 retransmit, return
* 1 0 0 nothing
* 1 0 1 nothing [impossible]
* 1 1 0 nothing
* 1 1 1 retransmit, return
*/
//重复ACK满3个,执行下面程序
void
RenoTcpAgent::dupack_action()
{
int recovered = (highest_ack_ > recover_);
int allowFastRetransmit = allow_fast_retransmit(last_cwnd_action_); //*上次是DUPACK状态,本次仍是重复ACK,允许本次快速重传
if (recovered || (!bug_fix_ && !ecn_) || allowFastRetransmit) { //*若允许快速重传,跳转
goto reno_action;
}
if (ecn_ && last_cwnd_action_ == CWND_ACTION_ECN) {
last_cwnd_action_ = CWND_ACTION_DUPACK;
/*
* What if there is a DUPACK action followed closely by ECN
* followed closely by a DUPACK action?
* The optimal thing to do would be to remember all
* congestion actions from the most recent window
* of data. Otherwise "bugfix" might not prevent
* all unnecessary Fast Retransmits.
*/
reset_rtx_timer(1,0);
output(last_ack_ + 1, TCP_REASON_DUPACK);
dupwnd_ = numdupacks_;
return;
}
if (bug_fix_) {
/*
* The line below, for "bug_fix_" true, avoids
* problems with multiple fast retransmits in one
* window of data.
*/
return;
}
reno_action:
// we are now going to fast-retransmit and will trace that event
trace_event("RENO_FAST_RETX"); //*跟踪RENO快速重传
recover_ = maxseq_; //更新recover_
last_cwnd_action_ = CWND_ACTION_DUPACK; //记录本次重复ACK
slowdown(CLOSE_SSTHRESH_HALF|CLOSE_CWND_HALF); //*SSTHRESH和CWND都降低一半
reset_rtx_timer(1,0); //*重设重传定时器,mild=1,使t_seqno_ != highest_ack_ + 1,保持原来的值
output(last_ack_ + 1, TCP_REASON_DUPACK); //*发送下一个未ACK的分组, from top
dupwnd_ = numdupacks_; //*发送窗口增加数
return;
}
void RenoTcpAgent::timeout(int tno)
{
if (tno == TCP_TIMER_RTX) {
dupwnd_ = 0;
dupacks_ = 0;
if (bug_fix_) recover_ = maxseq_;
TcpAgent::timeout(tno);
} else {
timeout_nonrtx(tno);
}
}
/*
* Copyright (c) 1990, 1997 Regents of the University of California.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by the University of California, Lawrence Berkeley Laboratory,
* Berkeley, CA. The name of the University may not be used to
* endorse or promote products derived from this software without
* specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
#ifndef lint
static const char rcsid[] =
"@(#) $Header: /nfs/jade/vint/CVSROOT/ns-2/tcp/tcp-reno.cc,v 1.42 2005/07/13 03:51:32 tomh Exp $ (LBL)";
#endif
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include "ip.h"
#include "tcp.h"
#include "flags.h"
static class RenoTcpClass : public TclClass {
public:
RenoTcpClass() : TclClass("Agent/TCP/Reno") {}
TclObject* create(int, const char*const*) {
return (new RenoTcpAgent());
}
} class_reno;
int RenoTcpAgent::window()
{
//
// reno: inflate the window by dupwnd_
// dupwnd_ will be non-zero during fast recovery,
// at which time it contains the number of dup acks
//
int win = int(cwnd_) + dupwnd_; //在快速恢复时,增加发送窗口,dupwnd_=0(初始)或者=numdupacks_,在dupack_>numdupacks_时,dupwnd_每次还要+1
if (frto_ == 2) {
// First ack after RTO has arrived.
// Open window to allow two new segments out with F-RTO.
win = force_wnd(2);
}
if (win > int(wnd_))
win = int(wnd_);
return (win);
}
double RenoTcpAgent::windowd()
{
//
// reno: inflate the window by dupwnd_
// dupwnd_ will be non-zero during fast recovery,
// at which time it contains the number of dup acks
//
double win = cwnd_ + dupwnd_;
if (win > wnd_)
win = wnd_;
return (win);
}
RenoTcpAgent::RenoTcpAgent() : TcpAgent(), dupwnd_(0)
{
}
void RenoTcpAgent::recv(Packet *pkt, Handler*)
{
hdr_tcp *tcph = hdr_tcp::access(pkt);
int valid_ack = 0;
if (qs_approved_ == 1 && tcph->seqno() > last_ack_)
endQuickStart();
if (qs_requested_ == 1)
processQuickStart(pkt);
#ifdef notdef
if (pkt->type_ != PT_ACK) {
fprintf(stderr,
"ns: confiuration error: tcp received non-ack/n");
exit(1);
}
#endif
/* W.N.: check if this is from a previous incarnation */
if (tcph->ts() < lastreset_) {
// Remove packet and do nothing
Packet::free(pkt);
return;
}
++nackpack_;
ts_peer_ = tcph->ts();
if (hdr_flags::access(pkt)->ecnecho() && ecn_)
ecn(tcph->seqno());
recv_helper(pkt);
recv_frto_helper(pkt);
if (tcph->seqno() > last_ack_) { //本ACK序号>上次记录的ACK序号,表示是新的ACK
if (last_cwnd_action_ == CWND_ACTION_DUPACK) //*本次新ACK,则退出快速重传
last_cwnd_action_ = CWND_ACTION_EXITED; //*
dupwnd_ = 0; //*设置dupwnd_=0,用于下次计算发送窗口win
recv_newack_helper(pkt);
if (last_ack_ == 0 && delay_growth_) { //是连接以来的第一个ACK
cwnd_ = initial_window(); //初始化CWND
}
} else if (tcph->seqno() == last_ack_) { // 本次不是新ACK,是上次的重复ACK
if (hdr_flags::access(pkt)->eln_ && eln_) {
tcp_eln(pkt);
return;
}
//以下是重复数ACK=1-2、3和3以上的三种情况的处理
if (++dupacks_ == numdupacks_) { //*默认numdupacks_=3,有3个重传就执行快速恢复和快速重传
dupack_action(); //改变SSTHRESH、CWND,并重设定时器超时
if (!exitFastRetrans_) //*exitFastRetrans_默认为1,reno专用
dupwnd_ = numdupacks_;
} else if (dupacks_ > numdupacks_ && (!exitFastRetrans_ //*超过numdupacks_次重传ACK,且上次也是重传ACK
|| last_cwnd_action_ == CWND_ACTION_DUPACK )) {
++dupwnd_; //* 执行快速恢复:在超过numdupacks_次重传ACK后,每次再收到一个重复ACK,使发送窗口+1,加快发送,fast recovery
} else if (dupacks_ < numdupacks_ && singledup_ ) { //如果是1次到2次重复ACK,发送一个新分组 ,这是限制传输机制
send_one();
}
}
if (tcph->seqno() >= last_ack_) //本ACK序号>=上次ACK,表示是新ACK或重复ACK,是合法的
// Check if ACK is valid. Suggestion by Mark Allman.
valid_ack = 1;
Packet::free(pkt); //合法,回收该分组内存
#ifdef notyet
if (trace_)
plot();
#endif
/*
* Try to send more data
*/
if (valid_ack || aggressive_maxburst_) //aggressive_maxburst_默认值为1
if (dupacks_ == 0 || dupacks_ > numdupacks_ - 1) //*如果是新的ACK或者重复ACK数>=3,尽量发送更多的数据
send_much(0, 0, maxburst_); //即如果重复ACK=1或者2,则不这样传,而按照上面只发送一个分组
}
/*注: 限制传输机制(Limited Transmit mechanism)
我们知道,当前的TCP应用主要有两种重传机制-快速重传和超时重传。当TCP源端收到3个ACK副本时,
就会触发快速重传机制,此时源端重传丢失的数据包并且将拥塞窗口大小减半。这种情况下,TCP流往往能
够很快从丢包中恢复过来,重新回到原先的发送速率。但如果TCP源端没有收到3个ACK副本,例如拥塞窗口
大小小于4,那么TCP源端则需要等待相当长时间,以便超时重发。这样,小窗口的TCP流就很容易陷入不必
要的超时重发,使其吞吐量大大下降。
为了避免这种不必要的超时重传,一种改进办法就是只要TCP源端收到一个或者两个ACK副本,并且如果
通告窗口允许,便继续发送新的数据包。这是因为只要收到ACK副本,就表明有数据包已经离开网络被接受
端接收了,而此时源端还无法判断数据包是否被丢弃,根据“数据包守恒”原则,只要遵守拥塞窗口的规范,
也即同时在网络中传送的数据包数量不能超过拥塞窗口的大小(以数据包为单位),源端就可以继续发送新
的数据包
4000
。这种机制称为限制传输机制(Limited Transmit mechanism),这种机制对排序的数据包尤其有效。
限制传输机制可以使小窗口的TCP流很快从丢包中恢复过来。例如,对于拥塞窗口大小为4地TCP流,如果
其第二个数据包丢失,那么按传统地做法需要等待超时重传。而在限制传输机制下,当源端收到对第三个数据
包确认的ACK副本时(ACK中要求源端发送第二个数据包),继续发送新的数据包,最终源端可以收到三个ACK
副本从而触发快速重传,从而减少了不必要的超时重传。
*/
//last_cwnd_action_即上次对CWND的动作为DUPACK,则本次允许快速重传 //本次
int
RenoTcpAgent::allow_fast_retransmit(int last_cwnd_action_)
{
return (last_cwnd_action_ == CWND_ACTION_DUPACK);
}
/*
* Dupack-action: what to do on a DUP ACK. After the initial check
* of 'recover' below, this function implements the following truth
* table:
*
* bugfix ecn last-cwnd == ecn action
*
* 0 0 0 reno_action
* 0 0 1 reno_action [impossible]
* 0 1 0 reno_action
* 0 1 1 retransmit, return
* 1 0 0 nothing
* 1 0 1 nothing [impossible]
* 1 1 0 nothing
* 1 1 1 retransmit, return
*/
//重复ACK满3个,执行下面程序
void
RenoTcpAgent::dupack_action()
{
int recovered = (highest_ack_ > recover_);
int allowFastRetransmit = allow_fast_retransmit(last_cwnd_action_); //*上次是DUPACK状态,本次仍是重复ACK,允许本次快速重传
if (recovered || (!bug_fix_ && !ecn_) || allowFastRetransmit) { //*若允许快速重传,跳转
goto reno_action;
}
if (ecn_ && last_cwnd_action_ == CWND_ACTION_ECN) {
last_cwnd_action_ = CWND_ACTION_DUPACK;
/*
* What if there is a DUPACK action followed closely by ECN
* followed closely by a DUPACK action?
* The optimal thing to do would be to remember all
* congestion actions from the most recent window
* of data. Otherwise "bugfix" might not prevent
* all unnecessary Fast Retransmits.
*/
reset_rtx_timer(1,0);
output(last_ack_ + 1, TCP_REASON_DUPACK);
dupwnd_ = numdupacks_;
return;
}
if (bug_fix_) {
/*
* The line below, for "bug_fix_" true, avoids
* problems with multiple fast retransmits in one
* window of data.
*/
return;
}
reno_action:
// we are now going to fast-retransmit and will trace that event
trace_event("RENO_FAST_RETX"); //*跟踪RENO快速重传
recover_ = maxseq_; //更新recover_
last_cwnd_action_ = CWND_ACTION_DUPACK; //记录本次重复ACK
slowdown(CLOSE_SSTHRESH_HALF|CLOSE_CWND_HALF); //*SSTHRESH和CWND都降低一半
reset_rtx_timer(1,0); //*重设重传定时器,mild=1,使t_seqno_ != highest_ack_ + 1,保持原来的值
output(last_ack_ + 1, TCP_REASON_DUPACK); //*发送下一个未ACK的分组, from top
dupwnd_ = numdupacks_; //*发送窗口增加数
return;
}
void RenoTcpAgent::timeout(int tno)
{
if (tno == TCP_TIMER_RTX) {
dupwnd_ = 0;
dupacks_ = 0;
if (bug_fix_) recover_ = maxseq_;
TcpAgent::timeout(tno);
} else {
timeout_nonrtx(tno);
}
}
相关文章推荐
- 好东西和大家分享阿!
- PHP技术分享--实现中文字串截取无乱码的函数(适用于utf-8)
- C# PDF Page操作——设置页面切换按钮 C# 添加、读取Word脚注尾注 C#为什么不能像C/C++一样的支持函数只读传参 web 给大家分享一个好玩的东西,也许你那块就用的到
- 好东西大家一起分享
- php中高性能中文字符串截取函数分享
- QB部分语句&函数的解释(中文)
- Asp.net无刷新中文验证码调试成功,特分享给大家
- C++中的类所占内存空间总结(其中有一段关于成员函数处于代码段的解释)
- 这是我们公司总结的一些关于中文乱码问题的一些解决方案和经验和大家分享!
- 给大家介绍个好东西,发短信,分享组件的提供商,支持ios和android。
- 大家注意vector, list, set, map成员函数erase
- 好东西大家分享: 怎么画数据流图
- 好东西大家分享:给所有想从事软件研发的年轻工程师的忠告与建议
- InstallShield中文函数解释
- 好东西大家一块分享
- php中解析带中文字符的url函数分享
- Asp.net无刷新中文验证码源码调试成功,特分享给大家
- 如何编写测试用例-好东西与大家分享
- 好东西大家分享:脚本语言
- 给大家分享一个PHP控制字符串输出函数案例吧