2

我第一次在 C++ 中使用 UDP 套接字,但我不确定我是否理解它们是如何工作的。我知道sendto/recvfromsend/recv通常返回实际发送或接收的字节数。我听说这个值可以任意小(但至少为 1),并且取决于套接字缓冲区中有多少数据(读取时)或缓冲区中剩余多少可用空间(写入时)。

如果sendtorecvfrom仅保证一次发送或接收 1 个字节,并且可以乱序接收数据报,那么任何 UDP 协议如何保持一致?这不是意味着当我收到消息中的字节时可以任意打乱它们吗?有没有办法保证一次发送或接收一条消息?

4

4 回答 4

3

它比那强一点UDP 确实提供了一个完整的包;缓冲区大小可以任意小,但它必须包含数据包中发送的所有数据。但也有大小限制:如果要发送大量数据,则必须将其分成数据包并自己重新组装。它也不能保证交货,因此您必须检查以确保一切顺利。

但是由于您可以使用 UDP 实现所有 TCP,因此它必须是可能的。

通常,您使用 UDP 所做的就是制作离散的小数据包。

打个比方,把 UDP 想象成发送明信片,把 TCP 想象成打电话。当您发送明信片时,您无法保证送达,因此您需要做一些事情,比如回复确认函。通过一个电话,您知道连接存在,并且您会立即听到答案。

于 2009-04-23T02:05:42.900 回答
1

不会。使用 sendto,您可以发送数据包,其中可以包含一个字节。如果您将 10 个字节作为单个 sendto 调用发送,这 10 个字节将被发送到一个数据包中,这将像您期望的那样被连贯地接收。

当然,如果您决定一个接一个地发送这 10 个字节,每个字节都带有一个 sendto 调用,那么实际上您发送和接收 10 个不同的数据包(每个包含 1 个字节),它们可以是任意顺序的。

这类似于通过邮政服务发送一本书。您可以将整本书打包到一个盒子中,或者撕下每一页并将每一页作为单独的信件发送。在第一种情况下,包裹比较大,但您收到的书是一个单独的、有序的实体。在后者中,每个包都很轻,但祝你好运;)

于 2009-04-23T02:12:44.147 回答
1

实际上你可以发送一个 0 字节长度的 UDP 数据报。发送的只是 IP 和 UDP 标头。另一端的 UDP recvfrom() 将返回长度为 0。与 TCP 不同,这并不意味着对等方关闭了连接,因为使用 UDP 没有“连接”。

于 2009-04-23T03:55:05.587 回答
1

我有一个客户端程序,它在专用于等待 UDP 套接字上的传入数据的线程中使用阻塞选择(NULL 超时参数)。即使它是阻塞的,select 有时也会返回一个指示单个读取描述符已“准备好”的指示。随后的 recvfrom 返回 0。

经过一些实验,我发现至少在 Windows 上,UDP 数据包发送到不期望它的主机上的端口会导致后续的 recvfrom 获得 0 字节。我怀疑某种拒绝通知可能来自另一端。我现在用它来提醒我,我忘记在服务器上启动查找客户端传入流量的进程。

顺便说一句,如果我改为“发送”一个有效但未使用的 IP 地址,则选择不会返回就绪状态并按预期阻止。我还发现阻塞与非阻塞套接字没有区别。

于 2012-03-21T15:21:56.483 回答