⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tcp-fast.c

📁 fast_tcp的源代码加上了自己对它的中文注释
💻 C
📖 第 1 页 / 共 3 页
字号:
#endif
	return (double)inst_cwnd;
}

/******************************************************************************/
/* parameter estimation */
void
FastTcpAgent::fast_est(Packet *pkt,double rtt)
{
	hdr_tcp *tcph = hdr_tcp::access(pkt);
	
	if(rtt < baseRTT_)
		baseRTT_ = rtt;			//始终保存最小的RTT为baseRTT_
	avg_cwnd_last_RTT_ = (fast_est_update_avg_cwnd(t_seqno_ - tcph->seqno() - dupacks_));//在该版本中fast_est_update_avg_cwnd函数始终都只返回参数值,即返回t_seqno_ - tcph->seqno() - dupacks_
	avgRTT_ = fast_est_update_avgrtt(rtt);//更新平均RTT值
}

/******************************************************************************/
/* congestion control */
void
FastTcpAgent::fast_cc(double rtt, double old_cwnd)
{
	// We update acks_last_rtt every RTT.	//记录最近一个RTT时间内收到的确认数保存在acks_last_rtt中
	if ( fast_calc_cwnd_end + rtt < currentTime )
	{
		fast_calc_cwnd_end = currentTime;
		acks_last_rtt = acks_per_rtt;	//保存最近一个RTT时间的确认数
		acks_per_rtt = 0;		//重新清零
		if ( on_first_rtt_ == true )	//反转on_first_rtt,当定义UPDATE_CWND_EVERY_OTHER_RTT时用于标识两次fast_update_cwnd_interval_时间间隔才更新一次窗口值
			on_first_rtt_ = false;
		else
			on_first_rtt_ = true;
	}
	acks_per_rtt++;			//累加该RTT内收到的确认数
	
	// We use MI to increase cwnd_ when there is little queueing delay
	if ( avgRTT_ - baseRTT_ < mi_threshold_ && (fast_opts & FAST_ALLOW_MI) )//有小部分的包排队延时时,使用加数增大窗口,防止窗口增大过快
	{
		cwnd_++;
		cwnd_update_time = currentTime;
		return;
	}
	
	// If queueing delay is large, we use fast algorithm
	if ( currentTime >= cwnd_update_time + fast_update_cwnd_interval_	//间隔fast_update_cwnd_interval_才计算一次新窗口大小
#ifdef	UPDATE_CWND_EVERY_OTHER_RTT
		&& on_first_rtt_ == true
#endif
	)
	{
		double updated_cwnd;
		cwnd_increments = 0;		//在fast_pace()中用于计算窗口步进值
		updated_cwnd = fast_calc_cwnd(cwnd_,old_cwnd);			//计算新窗口大小
		if ( updated_cwnd >= cwnd_ && baseRTT_ >= 0.004 && baseRTT_ != DOUBLE_VARABLE_INVALID_VALUE )//带宽不高且要增大窗口
		{
			fast_pace(&cwnd_, (int)(updated_cwnd-cwnd_));
		}
		else
			cwnd_ = updated_cwnd;
		cwnd_update_time = currentTime;
	}
	else if ( baseRTT_ >= 0.004 && baseRTT_ != DOUBLE_VARABLE_INVALID_VALUE )
		fast_pace(&cwnd_, 0);
}

#define MIN(x, y) ((x)<(y) ? (x) : (y))
/******************************************************************************/
void
FastTcpAgent::recv(Packet *pkt, Handler *)
{
	currentTime = fasttime();
	hdr_tcp *tcph = hdr_tcp::access(pkt);		//pkt偏移得到tcp头
	hdr_flags *flagh = hdr_flags::access(pkt);
	int valid_ack = 0;
	
	if (qs_approved_ == 1 && tcph->seqno() > last_ack_)
		endQuickStart();
	if (qs_requested_ == 1)
		processQuickStart(pkt);
	
	/* W.N.: check if this is from a previous incarnation */
	if (tcph->ts() < lastreset_)		//tcp->ts()返回该包的产生时间,因为对方重传包时.包产生时间不变.所以可以用来确定该包是否为重传的包
	{
		// Remove packet and do nothing
		Packet::free(pkt);
		return;
	}
	++nackpack_;
	if(firstrecv_<0)	//初始化时设为-0.1
	{ // init fast rtt vars
		firstrecv_ = currentTime;	//currentTime 是以firstsent_做为基准值开始计时的
		baseRTT_ = avgRTT_ = rtt_ = firstrecv_;		//接收到的第一个包的时间
	}
	
	if (flagh->ecnecho())
		ecn(tcph->seqno());
	
	int ecnecho = hdr_flags::access(pkt)->ecnecho();
	if (ecnecho && ecn_)
		ecn(tcph->seqno());
	// Check if ACK is valid.  Suggestion by Mark Allman.
	if (tcph->seqno() >= last_ack_)		//包的序号比之前已经确认收到的序号大.即有效包	
		valid_ack = 1;
	
#ifdef FASTTCPAGENT_DEBUG
	if (cwnd_ <= 0)
		printf("%8.3f : cwnd is not positive! cwnd is %f .\n", (double)currentTime, (double)cwnd_);
#endif
		/*
		* If DSACK is being used, check for DSACK blocks here.
		* Possibilities:  Check for unnecessary Fast Retransmits.
	*/
	if (!fastrecov_)
	{//未启用快恢复(快重传)
		/* normal... not fast recovery */
		if ((int)tcph->seqno() > last_ack_)	//收到比要确认包值更大的包,即提前收到了要接收的下一个包后面的包.也说明了要收的last_ack_未到达
		{
			if (last_ack_ == 0 )		//是第一个包
			{
				cwnd_ = initial_window();	//初始化窗口值
			}
			
			/* check if cwnd has been inflated */
#if 1
			if(dupacks_ > numdupacks_ &&  cwnd_ > newcwnd_)
			{
				//check t_seqno_ before changing cwnd.
				if (t_seqno_ < tcph->seqno())		
					t_seqno_ = tcph->seqno();
				//cwnd becomes a negative number in some case.
				
				cwnd_ = t_seqno_ - tcph->seqno() + 1;		//确保cwnd_最小为1
				dupacks_ = 0;
				for (int i=0;i<maxwnd_;i++)
					cwnd_array_[i]=cwnd_;
			}
#endif
			
			firstpartial_ = 0;
			
			// reset sendtime for acked pkts and incr transmits_
			double sendTime = sendtime_[tcph->seqno()%maxwnd_];
			double old_pif=cwnd_array_[tcph->seqno()%maxwnd_];
			int transmits = transmits_[tcph->seqno()% maxwnd_];
			for(int k= (last_natural_ack_number_+1); k<=tcph->seqno(); ++k)//last_natural_ack_number_+1到tcph->seqno()之间的包未到达
			{
				sendtime_[k%maxwnd_] = -1.0;
				transmits_[k%maxwnd_] = 0;
				cwnd_array_[k%maxwnd_]=-1;
			}
			if (t_seqno_ > tcph->seqno())
			{
				if ((transmits == 1) && (currentTime - sendTime > 0))
					rtt_ = currentTime - sendTime;
				else
					rtt_ = avgRTT_;
			}else
				rtt_ = avgRTT_;			//出现重传时不影响平均RTT的计算
			
			fast_recv_newack_helper(pkt);
			timeout_ = FALSE;
			scb_->ClearScoreBoard();
			fast_est(pkt, rtt_);
			fast_cc(rtt_, old_pif);			//拥塞控制
			last_natural_ack_number_ = tcph->seqno();	//最近收到的包序号;
		} else if ((int)tcph->seqno() < last_ack_)		//重复的包,即该已经确认收到了
		{
			/*NOTHING*/
			//the follows are if (int)tcph->seqno() == last_ack_
		} else if (timeout_ == FALSE)
		{
			if (tcph->seqno() != last_ack_)
			{
				fprintf(stderr, "pkt seq %d should be %d\n", tcph->seqno(), last_ack_);
				abort();
			}
			scb_->UpdateScoreBoard (highest_ack_, tcph);
			/*
			* Check for a duplicate ACK.
			* Check that the SACK block actually
			*  acknowledges new data.
			*/
			if(scb_->CheckUpdate())
			{
				if (++dupacks_ == numdupacks(cwnd_))
				{
				/*
				* Assume we dropped just one packet.
				* Retransmit last ack + 1
				* and try to resume the sequence.
					*/
					dupack_action();		//确认次数超过一定值.重传该包
				} else if (dupacks_ < numdupacks(cwnd_) && singledup_ )
				{
					send_one();		//发送新包
				}
			}
		}
		if (valid_ack || aggressive_maxburst_)
			if (dupacks_ == 0)
				send_much(FALSE, 0, maxburst_);		//将窗口中的包发完
	} else
	{//启用快恢复(快重传)
		/* we are in fast recovery */
		cwnd_update_time = currentTime;
		--pipe_;
		if ((int)tcph->seqno() >= recover_)
		{
			/* ACK indicates fast recovery is over */
			recover_ = 0;
			fastrecov_ = FALSE;
			newack(pkt);		//新的未确认的包到达
			/* if the connection is done, call finish() */
			if ((highest_ack_ >= curseq_-1) && !closed_)
			{
				closed_ = 1;
				finish();
			}
			timeout_ = FALSE;
			scb_->ClearScoreBoard();
			
			/* New window: W/2 - K or W/2? */
		} else if ((int)tcph->seqno() > highest_ack_)
		{
		/* Not out of fast recovery yet.
			* Update highest_ack_, but not last_ack_. */
			highest_ack_ = (int)tcph->seqno();	//更新确认序号,即收到的最大序号
			scb_->UpdateScoreBoard (highest_ack_, tcph);
			if (partial_ack_)
			{
				/* partial_ack_ is needed to guarantee that */
				/*  a new packet is sent in response to a   */
				/*  partial ack.                            */
				partial_ack_action();
				++pipe_;
				if (firstpartial_ == 0)
				{
					newtimer(pkt);
					t_backoff_ = 1;
					firstpartial_ = 1;
				}
			} else
			{
				--pipe_;
				newtimer(pkt);
				t_backoff_ = 1;
				/* If this partial ACK is from a retransmitted pkt,*/
				/* then we decrement pipe_ again, so that we never */
				/* do worse than slow-start.  If this partial ACK  */
				/* was instead from the original packet, reordered,*/
				/* then this might be too aggressive. */
			}
		} else if (timeout_ == FALSE)
		{
			/* got another dup ack */
			scb_->UpdateScoreBoard (highest_ack_, tcph);
			if(scb_->CheckUpdate())
			{
				if (dupacks_ > 0)
					dupacks_++;
			}
		}
		if (valid_ack || aggressive_maxburst_)
			send_much(FALSE, 0, maxburst_);
	}
	Packet::free(pkt);
}
	
/******************************************************************************/
void
FastTcpAgent::dupack_action()
{
	int recovered = (highest_ack_ > recover_);
	if (recovered || (!bug_fix_ && !ecn_))
	{
		goto sack_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);
		/*
		* There are three possibilities:
		* (1) pipe_ = int(cwnd_) - numdupacks_;
		* (2) pipe_ = window() - numdupacks_;
		* (3) pipe_ = maxseq_ - highest_ack_ - numdupacks_;
		* equation (2) takes into account the receiver's
		* advertised window, and equation (3) takes into
		* account a data-limited sender.
		*/
		if (singledup_ && LimTransmitFix_)
		{
			pipe_ = maxseq_ - highest_ack_ - 1;
		}
		else
		{
			// numdupacks(cwnd_) packets have left the pipe
			pipe_ = maxseq_ - highest_ack_ - numdupacks(cwnd_);
		}
		fastrecov_ = TRUE;		//启动快重传
		scb_->MarkRetran(highest_ack_+1);
		output(last_ack_ + 1, TCP_REASON_DUPACK);
		return;
	}
	
	if (bug_fix_)
	{
	/*
	* The line below, for "bug_fix_" true, avoids
	* problems with multiple fast retransmits in one
	* window of data.
		*/
		return;
	}
	
sack_action:
	// we are now going into fast_recovery and will trace that event
	trace_event("FAST_RECOVERY");
	
	recover_ = maxseq_;
	last_cwnd_action_ = CWND_ACTION_DUPACK;
	if (oldCode_)
	{
		pipe_ = int(cwnd_) - numdupacks(cwnd_);
	} else if (singledup_ && LimTransmitFix_)
	{
		pipe_ = maxseq_ - highest_ack_ - 1;
	}
	else
	{
		// numdupacks(cwnd_) packets have left the pipe
		pipe_ = maxseq_ - highest_ack_ - numdupacks(cwnd_);
	}
	slowdown(CLOSE_SSTHRESH_HALF|CLOSE_CWND_HALF);
	reset_rtx_timer(1,0);
	fastrecov_ = TRUE;
	scb_->MarkRetran(highest_ack_+1);
	output(last_ack_ + 1, TCP_REASON_DUPACK);	// from top
												/*
												* If dynamically adjusting numdupacks_, record information
												*  at this point.
	*/
	return;
}

/*
* Process a packet that acks previously unacknowledges data, but
* does not take us out of Fast Retransmit.
*

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -