我应该了解哪些关于UDP编程的知识?

17

我并不是说如何连接套接字。关于UDP编程,我需要了解哪些内容?

  • 我需要担心套接字中出现的坏数据吗?
  • 如果我发送了200字节,我应该假设会分别收到120和60字节吗?
  • 我是否需要担心另一个连接在同一端口上向我发送坏数据?
  • 如果数据没有到达,通常我可能要等多长时间才能看到数据(250毫秒?1秒?1.75秒?)

我真正需要知道什么?

12个回答

19

"如果我发送了200字节,我可能会分别收到120字节和60字节吗?"

当您发送UDP数据报时,读取的大小将等于写入的大小。这是因为UDP是一种数据报协议,而TCP是一种协议。但是,在数据包可能被路由器分段或丢弃之前,您只能写入MTU的大小。对于一般互联网使用,安全的MTU大小是576字节,包括头。

"我应该担心另一个连接在同一端口上向我发送了错误的数据吗?"

您没有连接,只有端口。无论来自哪里,您都将接收到发送到该端口的任何数据。您需要确定它是否来自正确的地址。

如果数据通常不到达,我可能需要多长时间才能看到数据(250ms?1秒钟?1.75秒?)

数据可能永久丢失、延迟或乱序到达。如果这些问题中的任何一个困扰您,请使用TCP。在UDP之上编写可靠的协议非常复杂,并且几乎所有应用程序都没有必要这样做。


我正在编写一些游戏代码,因此数据包丢失是可以接受的。我想知道在不接收任何数据的情况下应该等待多长时间(以便我可以确定需要等待多少帧)。 - user34537
2
我已经编写了许多商业游戏,通常情况下,仅仅因为这是一个游戏,并不意味着数据包丢失是可以接受的。当使用UDP协议时,我们通常会等待至少30秒钟,才确认用户是否完全链接中断。 - Don Neufeld
2
数据包丢失不应被视为正常现象,相反,你应该专注于减少发送数据。 正如Don所暗示的那样,数据包丢失可能意味着连接断开了 - 可能是高丢失率或突发的延迟。在游戏中使用UDP是一个经过充分研究的领域。知道你正在编写游戏时,在UDP上编写可靠的封装可能适用于这种情况。但是应该注意Don的警告 - 这并不容易。在网上搜索 - 有很多关于在游戏中正确使用UDP的好信息。 - Mark
据我所知,当读取TCP数据包时,我们先读取大小,然后再读取数据,但是当读取UDP数据包时,我们会读取整个数据包。这是因为“当你发送UDP数据报时,读取的大小将等于写入的大小”吗? - onmyway133

9

我应该担心另一个连接在同一端口上向我发送错误数据吗?

是的,您应该担心。任何应用程序都可以随时向您的开放UDP端口发送数据。 UDP的一个重要用途是多对一样式通信,您可以使用recvfrom返回的地址来区分多个对等方之间的通信。

但是,如果您想避免这种情况,并且只接受来自单个对等方的数据包,则可以在UDP套接字上调用connect。这会导致IP堆栈拒绝来自除您想要通信的主机:端口组合(套接字)之外的任何主机:端口组合的数据包。

在UDP套接字上调用connect的第二个优点是,在许多操作系统中,它可以显著提高速度/延迟。当您在未连接的UDP套接字上调用sendto时,操作系统实际上会暂时连接套接字,发送数据,然后断开套接字,从而增加了显着的开销。

使用已连接的UDP套接字的第三个优点是,它允许您将ICMP错误消息发送回您的应用程序,例如由于崩溃而导致的路由或主机未知。如果UDP套接字未连接,则操作系统将不知道从网络传递ICMP错误消息的位置,并会悄悄地丢弃它们,这可能会导致您的应用程序在等待来自崩溃主机的响应(或等待选择超时)时挂起。


很棒的信息。我从未考虑过连接。 - user34537

8

您的数据包可能无法到达目的地。

您的数据包可能会被发送两次或多次。

您的数据包可能不会按顺序到达。

底层网络层对您的数据包大小有限制。数据包大小可能非常小(可能为576字节)。

这并不意味着“不要使用UDP”。但是,您应该注意以上所有内容,并考虑您可能想要采取哪些恢复选项。


我记得听说过不按顺序,但却收到了相同的数据包两次!?!这是我从未想过的事情。 - user34537

6
IP层负责分割和重组,所以你不需要担心这个问题(这意味着你不会收到被分割或截断的数据包)(维基百科)。UDP数据包有一个用于数据和头部的校验和,因此接收虚假数据的可能性很小,但仍有可能出现丢失或重复的数据包。无拥塞控制,所以如果你计划使用大量的UDP数据包来堵塞管道,那么你需要考虑这一点。请务必检查你的数据。

还应该强调的是,当混合在一个存在明显丢包的环境中时(尽管假设分段正在工作,有时它会工作),分段特别需要关注,因为任何片段的丢失都意味着数据报将无法重新组装到目标IP堆栈。换句话说,当两个UDP套接字的路径丢失率很高时,分段会使数据报的故障有效率加倍。 - benc
1
非常正确。我应该用更好的措辞。您确实需要担心超过数据包路径上任何段的MTU可能性,从而导致分段,但是通过的任何数据包都会作为整体传递。 - TrayMan

4
我不会像其他回答者那样推荐TCP,因为除了登录/聊天信息之外,它与游戏无关。让我们按顺序来看:

我需要担心套接字中的错误数据吗?

是的。尽管UDP包含一个非常简单的校验和用于路由器等设备,但它并不是100%有效的。您可以添加自己的校验设备,但大多数情况下,当可靠性已经不是问题时,使用UDP,因此不符合规范的数据应该被丢弃。

如果我发送200字节,我应该假设我会分别收到120和60字节吗?

不,UDP是直接数据写入和读取。但是,如果数据太大,一些路由器将会截断数据,您将永久失去部分数据。有人说大约576字节带头文件,我个人不会使用超过256字节(好的2的对数)。

我应该担心另一个连接在同一端口上向我发送错误数据吗?

UDP侦听来自端口上任何计算机的任何数据,因此从这个意义上说是的。还要注意,UDP是原始格式,可以使用伪造的发送方,因此您应该使用某种“键”以便侦听器验证发送方是否与其IP地址匹配。

如果数据没有到达,我通常可能多长时间看不到数据(250毫秒?1秒?1.75秒?)

通过UDP发送的数据通常是一次性的,因此如果您没有收到数据,则可以轻松忽略它。但是,有时您需要“半可靠”,但又不想使用TCP所使用的“有序可靠”,1秒是一个很好的掉落估计值。您可以对旋转的数据包进行编号并编写自己的ACK通信。当接收到数据包时,它记录编号并发送回位域,让发送方知道它接收了哪些数据包。您可以阅读这份未完成的文档以获取更多信息(尽管未完成,但仍提供有价值的信息): http://gafferongames.com/networking-for-game-programmers/

4
UDP是一种无连接协议。通过UDP发送数据可以到达接收方,但在传输过程中也可能会丢失。UDP非常适合广播和流式音频或视频等场景(在这些情况下,丢失的数据包通常不会造成问题)。因此,如果您需要确保数据到达另一侧,请使用TCP。
与TCP相比,UDP的开销较小,因此速度更快。(TCP需要首先建立连接,并检查数据包是否损坏,这需要时间。)
分段的UDP数据包(即大约超过0.5Kb的数据包)可能会被路由器丢弃,因此在发送之前将数据拆分为小块。(在某些情况下,操作系统可以处理它。)请注意,只有一个完整的数据包才会被处理,而不会处理一半的数据包。
长距离的延迟可能很大。如果您想重传数据,则可以选择当前连接的平均延迟时间的5到10倍。(您可以通过发送和接收几个数据包来测量延迟。)
希望这可以帮助您。

很棒的东西。特别是“成功或失败”,另一位发帖者让我担心部分数据包。你说的重传数据是什么意思?在考虑失败之前,等待延迟时间(比如60毫秒)*5到10倍? - user34537
在建立会话时,您可以测量延迟时间。例如,向目标发送5个小的UDP数据包,并让其用4个数据包回复,测量往返所需的平均时间,并将其作为会话其余部分的基础。如果您有长时间运行的会话,则可能需要在某个时候重复此过程。 - Jeroen Landheer

3

在尝试使用UDP时需要知道的重要事情是:

你的数据包可能无法全部传输,这意味着可能会出现数据损坏。

如果你正在开发一个应用程序,其中100%的数据需要可靠地到达以提供功能,请使用TCP。如果你正在开发一个允许一些丢失的应用程序(如流媒体等),那么选择UDP,但不要期望所有数据从一个管道传输到另一个管道时都完好无损。


2
除了 don.neufeld 推荐使用 TCP 之外,
对于大多数应用程序来说,TCP 更容易实现。如果您需要在 TCP 流中维护数据包边界,则一种好的方法是在数据前传输一个两个字节的标头以分隔消息。标头应包含消息长度。在接收端只需读取两个字节并评估该值。然后等待直到您接收到这么多字节。你现在有了一个完整的消息,并准备接收下一个2字节标头。
这为您提供了 UDP 的一些好处,而无需担心丢失数据、无序数据包到达等问题。

我不需要所有的数据就能到达另一边,这也是针对类似原型游戏的。 - user34537

2

UDP和TCP适用的应用不同,可以这样理解:当数据传输“迟到总比不到好”时,TCP是很好的选择;而当数据传输“宁愿不到也不能迟到”时,UDP更为合适。

另一个方面是,大多数基于UDP的应用程序具有无状态、尽力而为的特点,这使得可扩展性更容易实现。此外,请注意UDP可以进行组播,而TCP不能。


1

不要假设你发送了一个数据包就一定能够到达目的地。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接