avatar

计算机网络作业3-3 拥塞控制算法

3-3:拥塞控制算法

在任务3-2的基础上,选择实现一种拥塞控制算法,也可以是改进的算法,完成给定测试文件的传输。

*注:由于是基于任务3-2上做的拥塞控制算法改进,只修改了窗口大小,故报文格式等内容不在重复。

注:快速重传只重传收到冗余ack的对应一条报文,不是重传base到sendnextseq之间的所有内容

拥塞控制算法

状态机

image-20201225212734579

初始状态:慢启动

  • 窗口大小为1,阈值32
  • 如果收到新的ACK,窗口大小+1,效果为单位时间内呈指数增长
  • 如果收到冗余ACK,标记,若连续收到三次冗余ACK
    • 启动快速重传
    • 阈值设为窗口大小的一半
    • 窗口大小设置为阈值+3
    • 进入快速恢复阶段
  • 窗口大小>=阈值时,进入拥塞避免阶段
  • 超时没有收到新的ACK
    • 阈值=窗口大小/2
    • 窗口大小=1
    • 重新进入慢启动阶段

拥塞避免

  • 每收到一个新的ACK,窗口大小增长为1/窗口大小,即单位时间呈线性增长
  • 如果收到冗余ACK,标记,若连续收到三次冗余ACK
    • 启动快速重传
    • 阈值设为窗口大小的一半
    • 窗口大小设置为阈值+3
    • 进入快速恢复
  • 超时没有收到新的ACK
    • 阈值=窗口大小/2
    • 窗口大小=1
    • 重新进入慢启动阶段

快速恢复

  • 每收到一个冗余的ACK,窗口大小+1,直到窗口大小>=阈值,进入拥塞避免阶段

代码

DWORD WINAPI recvhandler(LPVOID lparam)
{
printwindow();
int i = (int)(LPVOID)lparam;
//cout << "接收" << i << endl;
clock_t finalovertime;
int t = 0;
while (base < buffersize)
{
if (sendnextseq > base + N || sendnextseq == base)//窗口已满(对方还没有发送ack)或者窗口为空
Sleep(2);
message a;
simplerecv(a);
if (a.get_ack())//收到确认消息且序号正确
{
clockstart = clock();//重置计时器
if (a.ackseq >= base)//收到正确的消息序号
{
if (constatus == 0)
{
N += a.ackseq - base + 1;//累积确认
if (N >= ssthresh)
constatus = 1;//拥塞避免

}
else if (constatus == 1)
{
N += (a.ackseq - base + 1) / N;//线性增长
}
printwindow();
base = a.ackseq + 1;
overtime = 0;
t = 0;
}
else if (a.ackseq <= base-1)
{
t++;
cout << t << endl;
printwindow();
if (constatus == 2) {//快速恢复
N += 1;
if (N >= ssthresh) constatus = 1;//进入拥塞避免阶段
}
if (t == 3)//三个冗余ack
{
constatus = 2; //快速重传
overtime = 1;
}
}
}
clockend = clock();
}
cout << "exitpoint2" << endl;
return 1;
}
DWORD WINAPI sendhandler(LPVOID lparam)//发线程
{
int flag = 0;
clock_t s = clock();
while (base < buffersize)
{
int i = (int)(LPVOID)lparam;
if (!overtime)
{
int temp = base;
if (base + N == sendnextseq)
Sleep(40);
for (; sendnextseq < base + N && sendnextseq < buffersize; sendnextseq++)
{
flag = 0;//正常发送

if (!overtime)
{
simplesend(msgsend[sendnextseq]);
s = clock();
//Sleep(20);
}

else {
break;
}
simplesend(msgsend[sendnextseq]);
if (temp == base)
{
clock_t e = clock();
if ((e - s) / CLOCKS_PER_SEC >= WAIT_TIME)//超时重发
{
overtime = 1;
sendnextseq++;
break;
}
}
}
}
if (overtime == 1)//重新发送
{
if (constatus == 1 || constatus == 0)
{
ssthresh = N / 2;
N = 1;
constatus = 0;//重新进入慢启动阶段
printwindow();
}
else if (constatus == 2)
{//快速重传
ssthresh = N / 2;
N = ssthresh + 3;
}
if (flag)
Sleep(10);//减少重传次数
for (int i = base; i < sendnextseq; i++)
{
//重新发送
if (overtime)
simplesend(msgsend[i]);
else break;
flag++;
}
overtime = 0;//重传标识归0
s = clock();//重置计时器
}
clock_t e = clock();
if ((e - s) / CLOCKS_PER_SEC >= WAIT_TIME)//超时重发
overtime = 1;
}
cout << "exitpoint1" << endl;
return 0;
}
Author: Michelle19l
Link: https://gitee.com/michelle19l/michelle19l/2021/01/15/大三上/计网/计网作业3-3/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付寶
    支付寶