0

嗨,我有一台服务器通过 UDP 与客户端通信。基本上,客户端流向服务器 UDP 数据包。每个数据包由标头和有效负载组成。在标题中,只有一个短整数 - 我称之为 seqnum,从 0 到 SHORT_MAX。当客户端在发送时达到 SHORT_MAX 时,它会再次从 0 开始。

在服务器上,我需要以这种方式重建流:

a) 如果数据包到达时带有预期的 seqnum 附加到流。

b) 如果数据包以低于预期的 seqnum 到达 - 丢弃它 - 它是迟到的数据包

c) 如果数据包到达的 seqnum 比预期的高 - 将预期和实际 seqnum 之间的数据包视为丢失并尝试重建它们,然后附加实际数据包

我现在正在处理与计数器溢出有关的两个问题:

1) 如何检测情况 c) 在 SHORT_MAX 边界上(例如,预期是 SHORT_MAX-2,数据包中的实际 seqnum 是 2) - 在我的场景中,它会被错误地检测为情况 b)

2) 与情况 b) 相同的问题被错误地检测为 c)

多谢

4

3 回答 3

2

假设这SHORT_MAX实际上意味着SHRT_MAX,那么如果您找到方案 2,您将丢失大约 30000 个数据包。这可能意味着您无论如何都无法重建,并且链接已经出错了很长一段时间。您可以通过“超时”来解决这个问题(例如,如果在 X 秒内没有收到正确的数据包,请放弃并在某个合适的时间点重新开始 - 或者如果大量数据包丢失,您可以做的任何事情 - 您当然可以通过拔下电缆或类似的东西进行测试)。

你可以通过做一些模数学来检测“环绕”。

#include <iostream>
#include <algorithm>

using namespace std;

#define MAX_SEQ_NO 16
#define THRESHOLD  6    // Max number of "missing packets" that is acceptable

void check_seq_no(int seq_no)
{
    static int expected = 0;

    cout << "Got seq_no=" << seq_no << " expected=" << expected << endl;
    if (seq_no == expected)
    {
        expected = (expected + 1) % MAX_SEQ_NO;
    }
    else
    {
        if ((seq_no + THRESHOLD) % MAX_SEQ_NO > (expected + THRESHOLD) % MAX_SEQ_NO)
        {
            int missing;
            if (seq_no > expected)
            {
                missing = seq_no - expected;
            }
            else
            {
                missing = MAX_SEQ_NO + seq_no - expected;
            }
            cout << "Packets missing ..."  << missing << endl;
            expected = (seq_no+1) % MAX_SEQ_NO;
        }       
        else
        {
            cout << "Old packet received ... " << endl;
        }
    }
}

int main()
{
    int seq_no = 0;

    bool in_sim = false;
    int old_seq_no = 0;

    for(;;)
    {
        int r = rand() % 50; 

        if (!in_sim)
        {
            old_seq_no = seq_no;
            switch(r)
            {
                // Low number: Resend an older packet
            case 4:
                seq_no --;
            case 3:
                seq_no --;
            case 2:
                seq_no --;
            case 1:
                seq_no --;
                in_sim = true;
                break;

            // High number: "lose" a packet or four.
            case 46:
                seq_no++;
            case 47:
                seq_no++;
            case 48:
                seq_no++;
            case 49:
                seq_no++;
                in_sim = true;
                break;

            default:
                break;
            }
            if (old_seq_no > seq_no)
            {
                cout << "Simulating resend of old packets: " << old_seq_no - seq_no << endl;
            }
            else if (old_seq_no < seq_no)
            {
                cout << "Simulating missing packets: " << seq_no - old_seq_no << endl;
                old_seq_no = seq_no;
            }

        }
        if (old_seq_no == seq_no)
        {
            in_sim = false;
        }

        check_seq_no(seq_no % MAX_SEQ_NO);
        seq_no++;
   }
}
于 2013-07-05T22:36:05.607 回答
1

我建议,只要您在某个接近 SHORT_MAX 的阈值内获得数据包,并且它在类似的阈值 0 内,您就将其视为重建的候选对象。您还可以通过在客户端和服务器之间建立一个健全的确认系统来补偿数据包的丢失。少将此视为“重建”问题,因为它是一个优先级问题,您必须丢弃“旧”或可能重新传输的数据。

我过去使用的另一个策略是根据阈值、ACKing 和整体可靠性来定义具有(可能)不同配置的通道。在理想的世界中,您将拥有 100% 可靠的数据包(TCP 样式,保证按顺序交付)和 100% 不可靠的数据包,然后可能是介于两者之间的流——基于 UDP 的良好协议会支持这些。这使您的应用程序代码可以更直接地控制协议的算法,这是 UDP 的真正意义所在,它在游戏和视频等应用程序中大放异彩。

您可能会发现您经常重新实现 TCP 的一些部分,您甚至可能考虑将 TCP 用于您的 100% 可靠通道——值得注意的是,主干网通常会优先考虑 TCP,因为他们知道他们最终会拥有重新传输这些数据包,如果他们在这次旅行中没有通过。

于 2013-07-05T21:42:30.010 回答
0

为什么不使用无符号短,你会得到两倍的收益。对于您评论的那些情况,您需要指定一个阈值。这是您需要面对的两难境地,我的意思是,如果您期待数据包 30 并收到数据包 60,那么它是正确的数据包还是丢失的旧数据包。这就是为什么你需要设置一个阈值
例如;

If (NumberReceived < NumerberExpected)  
{
      threshold = (USHRT_MAX - NumerberExpected) + NumberReceived ;
      // in here you have to decided how many is the threshold  10, 20, 50 …
      if (threshold < 10) It is a correct packet and has started over
      else It is a lost packet
} 
else
     If (NumberReceived > NumerberExpected)  
     {
        threshold = NumerberReceived - NumberExpected ;
        // in here you have to decided how many is the threshold  10, 20, 50 …
        if (threshold < 10) It is a correct packet and I've lost some packets
        else It is a lost packet; 
     }
     else It is a correct packet
于 2013-07-05T22:48:18.610 回答