【问题标题】:UDP datagram countingUDP数据报计数
【发布时间】:2013-07-05 21:23:55
【问题描述】:

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

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

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

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

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

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

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

2) 同样的问题 b) 被错误地检测为 c)

非常感谢

【问题讨论】:

  • (C) 需要一个合理大小的窗口。任何比你现在所在位置早十个的数据包编号要么是一个错误,要么至少是不切实际的遥远,应该被丢弃。

标签: c++ udp


【解决方案1】:

假设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++;
   }
}

【讨论】:

  • 好的,基本上这应该是 TCP 解决的基本方法,对吗?
【解决方案2】:

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

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

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

【讨论】:

  • 事实上,这是实时流,所以我不关心重新传输 too late 数据包,因为它们已经迟到了,所以丢弃它们就可以了(编解码器会照顾丢失的数据包)。而且我认为,这绝对是比 prio 问题更多的 reconstruction - 没有重传,只有可能的情况是我写的。
  • 啊,我在这里找到了解决方案:stackoverflow.com/questions/5713724/…,我将不得不选择en.wikipedia.org/wiki/Sliding_window_protocol
【解决方案3】:

为什么不使用无符号短,你会得到两倍的收益。对于您评论的那些情况,您需要指定一个阈值。这是您需要面对的两难境地,我的意思是,如果您期待数据包 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

【讨论】:

  • 感谢您的回复,但我想以编程方式解决它 - 数据包计数可以无限制。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-07
  • 2011-05-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多