我们有一个通过 UDP 执行通信的系统(用 C 语言构建)。最近我们发现有必要保证数据包的传递。我的问题是:为确保使用 ack 数据包进行传递,基于 UDP 的系统的最少添加是多少?此外,理想情况下无需操作数据包标头。我们对数据包进行应用程序级别的控制,包括序列号和 ack/nack 标志。我想知道这是否是一个失败的原因,我们尝试做的任何事情基本上都是有缺陷和损坏的 TCP 版本。基本上,我们是否可以进行最低限度的改进来实现有保证的交付(我们不需要 TCP 的许多功能,例如拥塞控制等)。谢谢!
5 回答
TCP 将 3 个可能相关的服务交织在一起(好吧,TCP 做得更多,但我只讨论 3 个。)
- 按订单发货
- 可靠的交货
- 流量控制
您刚刚说您不需要流量控制,所以我什至不会解决这个问题(您将如何宣传窗口大小等,除了您可能需要一个窗口。我会解决的。 )
您确实说过您需要可靠的交付。这并不难——你使用 ACK 来表明发送者已经收到了一个数据包。基本的可靠交付如下所示:
- 发送方发送数据包
- Receiver接收到数据包,然后发送一个ack
- 如果发送者没有得到确认(通过计时器),他会重新发送数据包。
这三个步骤没有解决这些问题:
- 如果 ACK 丢失了怎么办?
- 如果数据包乱序到达怎么办?
因此,对于您的应用程序,您说您只需要可靠的交付 - 但没有说需要它们按顺序排列。这将影响您实现协议的方式。
(顺序无关紧要的示例:您正在将员工记录从一台计算机复制到另一台计算机。如果 Alice 的记录在 Bob 之前收到并不重要,只要两者都到达那里。)
因此,假设您只需要可靠(因为这就是您在帖子中所说的),您可以通过多种方式实现这一目标。
您的发件人可以跟踪未确认的数据包。所以如果它发送#3、4、5和6,并且没有得到3和4的ACK,那么发送者就知道它需要重传。(虽然发送方不知道数据包 3 和 4 是否很多,或者它们的 ACK 是否丢失。无论哪种方式,我们都必须重新传输。)
但是你的发送者可以做累积的 ACK——所以在上面的例子中,如果它收到了 3、4 和 5,它只会确认 #6。这意味着如果接收者之前没有收到数据包 6,它会丢弃数据包 6 . 如果您的网络非常可靠,那么这可能不是一个糟糕的选择。
然而,上述协议确实有一个窗口——即发送方一次发送多少个数据包?这意味着您确实需要某种窗口,但不是出于流量控制的目的。你将如何传输窗口大小?
你可以在没有窗口的情况下做到这一点,要么让窗口大小保持不变,要么做一些类似停止等待的事情。前者可能是更好的选择。
无论如何,我还没有直接回答你的问题,但我希望我已经指出了一些在构建它时值得考虑的事情。在没有部分流控制(如窗口)且不考虑有序的情况下进行“可靠传输”的任务非常困难!(让我知道我是否应该提供有关其中一些内容的更多详细信息!)
祝你好运!
看看 Steven 的UNIX 网络编程,第 1 卷的第 8 章和第 20 章。他涵盖了许多不同的方法。第 20.5 节“为 UDP 应用程序添加可靠性”可能是您最感兴趣的。
我有一个问题在这里运行,它正在收集“当你需要可靠的 UDP 时你可以使用什么”的答案。答案可能比您想要或需要的要多得多,但您可能可以查看一些基于 UDP 构建的协议并仅获取您需要的 ACK 部分。
从我使用 ENet 协议(一种可靠的 UDP 协议)的工作来看,我希望您在每个 UDP 数据报中都需要一个序列号,这是一种为您收到的数据报发送 ACK 的方法,一种保留您收到的数据报的方法'已经发送,直到您收到他们的 ACK 或他们超时,以及一种计时重新发送您尚未收到 ACK 的数据报的方法......当您决定您永远不会时,我还会添加一个整体超时将交付一个特定的数据报,并且,我猜,一个回调到您的应用程序层,以通知它未能交付......
实现 ack 的最佳方式是在应用层进行。CoAP 是在 udp 上运行但提供可靠数据传输的应用程序协议的一个示例。它为所有 Confirmable(CON) 消息保留一个消息 id,并发送一个接收者发送一个具有相同消息 id 的 ack 数据包。所有的 ack 和 message id 字段都保存在应用层部分。因此,如果发送方没有收到带有他发送的消息 id 的 Ack 数据包,它会重新传输该数据包。应用程序开发人员可以修改协议以适应可靠数据传输的需要。