skywind3000 / kcp

:zap: KCP - A Fast and Reliable ARQ Protocol
MIT License
15.36k stars 2.5k forks source link

当包大小大于MTU时,开启流控,只发首包? #342

Closed starcwl closed 2 years ago

starcwl commented 2 years ago

不开流控则没有这个问题。

复现 demo `

include

include

include "test.h"

include "ikcp.c"

// 模拟网络 LatencySimulator *vnet;

// 模拟网络:模拟发送一个 udp包 int udp_output(const char buf, int len, ikcpcb kcp, void user) { union { int id; void ptr; } parameter; parameter.ptr = user; vnet->send(parameter.id, buf, len); printf("output len id %d %d \n", parameter.id, len); return 0; }

// 测试用例 void test(int mode) { // 创建模拟网络:丢包率10%,Rtt 60ms~125ms vnet = new LatencySimulator(0, 0, 12);

// 创建两个端点的 kcp对象,第一个参数 conv是会话编号,同一个会话需要相同
// 最后一个是 user参数,用来传递标识
ikcpcb *kcp1 = ikcp_create(0x11223344, (void*)0);
ikcpcb *kcp2 = ikcp_create(0x11223344, (void*)1);

// 设置kcp的下层输出,这里为 udp_output,模拟udp网络输出函数
kcp1->output = udp_output;
kcp2->output = udp_output;

IUINT32 current = iclock();
IUINT32 slap = current + 20;
IUINT32 index = 0;
IUINT32 next = 0;
IINT64 sumrtt = 0;
int count = 0;
int maxrtt = 0;

// 配置窗口大小:平均延迟200ms,每20ms发送一个包,
// 而考虑到丢包重发,设置最大收发窗口为128
ikcp_wndsize(kcp1, 128, 128);
ikcp_wndsize(kcp2, 128, 128);

// 判断测试用例的模式
if (mode == 0) {
    // 默认模式
    ikcp_nodelay(kcp1, 0, 10, 0, 0);
    ikcp_nodelay(kcp2, 0, 10, 0, 0);
}
else if (mode == 1) {
    // 普通模式,关闭流控等
    ikcp_nodelay(kcp1, 0, 10, 0, 1);
    ikcp_nodelay(kcp2, 0, 10, 0, 1);
}   else {
    // 启动快速模式
    // 第二个参数 nodelay-启用以后若干常规加速将启动
    // 第三个参数 interval为内部处理时钟,默认设置为 10ms
    // 第四个参数 resend为快速重传指标,设置为2
    // 第五个参数 为是否禁用常规流控,这里禁止
    ikcp_nodelay(kcp1, 2, 10, 2, 1);
    ikcp_nodelay(kcp2, 2, 10, 2, 1);
    kcp1->rx_minrto = 10;
    kcp1->fastresend = 1;
}

ikcp_setmtu(kcp1, 1000);

char buffer[2000];
int hr;

for (int i = 0; i < 2000; i++)
{
    buffer[i]=i;
}

IUINT32 ts1 = iclock();

ikcp_update(kcp1, iclock());
ikcp_update(kcp2, iclock());
ikcp_send(kcp1, buffer, 1400);
while (1) {
    isleep(1);
    current = iclock();
    ikcp_update(kcp1, iclock());
    ikcp_update(kcp2, iclock());

    // 处理虚拟网络:检测是否有udp包从p1->p2
    while (1) {
        hr = vnet->recv(1, buffer, 2000);
        if (hr < 0) break;
        // 如果 p2收到udp,则作为下层协议输入到kcp2
        ikcp_input(kcp2, buffer, hr);

    }

    // kcp2接收到任何包都返回回去
    while (1) {
        hr = ikcp_recv(kcp2, buffer, 2000);
        // 没有收到包就退出
        if (hr < 0) break;
        // 如果收到包就回射
        ikcp_send(kcp2, buffer, hr);
    }

}

ts1 = iclock() - ts1;

ikcp_release(kcp1);
ikcp_release(kcp2);

const char *names[3] = { "default", "normal", "fast" };
printf("%s mode result (%dms):\n", names[mode], (int)ts1);
printf("avgrtt=%d maxrtt=%d tx=%d\n", (int)(sumrtt / count), (int)maxrtt, (int)vnet->tx1);
printf("press enter to next ...\n");
char ch; scanf("%c", &ch);

}

int main() { test(0); // 默认模式,类似 TCP:正常模式,无快速重传,常规流控 // test(1); // 普通模式,关闭流控等 // test(2); // 快速模式,所有开关都打开,且关闭流控 return 0; }

/* default mode result (20917ms): avgrtt=740 maxrtt=1507

normal mode result (20131ms): avgrtt=156 maxrtt=571

fast mode result (20207ms): avgrtt=138 maxrtt=392 */

`

skywind3000 commented 2 years ago

你为啥帖个源代码都帖不对?别人怎么帮你看?