Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

修复ikcp_check返回current, ikcp_upate可能不会调ikcp_flush #48

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

XiongMing
Copy link

ikcp_check检测到有需要重发的segment,但是没有更新 ts_flush,ikcp_update可能判断不需要flush,直接返回

@acynothia
Copy link

check 的目的应该是减少 update 的调用而不是替代. check 返回的时间可以用于自己的定时器来调度 update 调用的时机. 这样改似乎和本意不符啊.

@skywind3000
Copy link
Owner

是这么回事情,check就是check,这次update没有触发到flush,check会返回个很短的时间回来,下次就能触发。再你实在想每次check到就flush,你可以调用完update后,手动调用一次flush啊。

@XiongMing
Copy link
Author

while(true) { wait=check(); sleep(wait); update(); }
我测试的时候代码写成了这样,如果有resendts超时,check返回wait=0,update又没触发flush,接着继续check返回wait=0。直到update真正调用flush,这段时间内cpu会空转。

我理解,如果check到resents超时,这时候有片需要重发,应该是要通过update调一下flush的。如果直接调flush, ts_flush不会被设置。

另外,也可以在update里检测一下所有的resendts来避免这个问题。

Copy link

@nirvanan nirvanan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reasonable

@murshex
Copy link

murshex commented Oct 24, 2022

@skywind3000 Is this worth it?

@skywind3000
Copy link
Owner

直接调 flush 呗

@Homqyy
Copy link
Contributor

Homqyy commented Nov 8, 2022

我在epoll中集成KCP也遇到这个问题。

我的设计是:
1. 创建一个kcp timer的红黑树,每次创建kcp时都会插入到此树中。当时间到了后(expired)会顺序调用ikcp_update -> ikcp_check -> update_timer,伪代码如下:

while(1)
{
    kcp = get_min(kcp_rbtree);  // 获取最小的kcp节点

    if (kcp is null) break; // 空树,直接退出

    if (is_expired(kcp))
    {
        ikcp_update(kcp, current);
        timer = ikcp_check(kcp, current);
        update_timer(kcp_rbtree, kcp, timer);
    }
    else
    {
        break;
    }
}
  1. 每次 ikcp_input/ikcp_send/ikcp_flush 都会去更新当前kcp定时器的timeout值。

在上述第1条有一处:ikcp_update -> ikcp_check -> update_timer 的一个流程,现在出现问题:
1. ikcp_check返回的时间是current(当前时间),因此update_timer之后kcp.timer的时间仍旧是current
2. 这时候更新后的kcp.timer在定时器的逻辑判断中仍旧是expired,因此再次触发更新流程,因此会在此无限循环。

@Homqyy
Copy link
Contributor

Homqyy commented Nov 8, 2022

我在epoll中集成KCP也遇到这个问题。

我的设计是: 1. 创建一个kcp timer的红黑树,每次创建kcp时都会插入到此树中。当时间到了后(expired)会顺序调用ikcp_update -> ikcp_check -> update_timer,伪代码如下:

while(1)
{
    kcp = get_min(kcp_rbtree);  // 获取最小的kcp节点

    if (kcp is null) break; // 空树,直接退出

    if (is_expired(kcp))
    {
        ikcp_update(kcp, current);
        timer = ikcp_check(kcp, current);
        update_timer(kcp_rbtree, kcp, timer);
    }
    else
    {
        break;
    }
}
  1. 每次 ikcp_input/ikcp_send/ikcp_flush 都会去更新当前kcp定时器的timeout值。

在上述第1条有一处:ikcp_update -> ikcp_check -> update_timer 的一个流程,现在出现问题: 1. ikcp_check返回的时间是current(当前时间),因此update_timer之后kcp.timer的时间仍旧是current; 2. 这时候更新后的kcp.timer在定时器的逻辑判断中仍旧是expired,因此再次触发更新流程,因此会在此无限循环。

按照作者的答复来看,当ikcp_check返回了current时,手动调用ikcp_flush即可。在ikcp_check中不应当存在副作用,即刷新ts_flush

但是,我手动ikcp_flush之后,又该设置kcp.timer呢?再次ikcp_check

@Homqyy
Copy link
Contributor

Homqyy commented Nov 8, 2022

经过调整后,有效,伪代码如下:

while(1)
{
    kcp = get_min(kcp_rbtree);  // 获取最小的kcp节点

    if (kcp is null) break; // 空树,直接退出

    if (is_expired(kcp))
    {
        ikcp_update(kcp, current);
        timer = ikcp_check(kcp, current);
        update_timer(kcp_rbtree, kcp, timer);

        if (kcp.timer is current)
        {
            ikcp_flush(kcp);
            timer = ikcp_check(kcp, current);
            update_timer(kcp_rbtree, kcp, timer);
        }
    }
    else
    {
        break;
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants