UDP是IPC的可靠协议吗?
Posted
技术标签:
【中文标题】UDP是IPC的可靠协议吗?【英文标题】:Is UDP a reliable protocol for IPC? 【发布时间】:2016-09-05 22:59:45 【问题描述】:如果我纯粹将 UDP 用于进程间通信(即在 1 个系统中,不涉及网络),我可以认为它是可靠的吗?还是我还需要担心丢包等问题?
注意这是一个实践问题,而不是理论问题。如果答案因操作系统而异,请说明具体情况,尤其包括 Windows、Linux 和 Mac。
编辑:不,它不可靠——下面的例子。
感谢当前答案为我指明了正确的方向。
此代码在 Windows 8.1 上丢弃了一个数据包(我得到 Received: 18432 (DROPPED PACKET)
)。
(我不确定为什么它不能在 Linux 上运行,但它应该接近工作了。)
#include <stdio.h>
#ifdef _WIN32
#include <ws2tcpip.h>
#else
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#endif
int main()
#ifdef _WIN32
typedef int socklen_t;
#else
typedef int SOCKET;
#endif
SOCKET r = socket(AF_INET, SOCK_DGRAM, 0);
struct sockaddr_in addr = AF_INET ;
addr.sin_addr.s_addr = htonl(0x7F000001);
socklen_t addrlen = sizeof(addr);
if (bind(r, (struct sockaddr *)(&addr), addrlen) == -1 ||
getsockname(r, (struct sockaddr *)(&addr), &addrlen) == -1)
return 1;
SOCKET s = socket(AF_INET, SOCK_DGRAM, 0);
int tids = 0;
for (long c = 0, i = 0, j = 0; c < 1000000; ++c)
if ((c + 1) % 10)
int n = sendto(s, (char const *)(&i), sizeof(i), 0, (struct sockaddr const *)(&addr), sizeof(addr));
if (n != sizeof(i)) return 1;
// else fprintf(stderr, "Sent: %lu\n", i);
++i;
else
struct sockaddr temp;
socklen_t templen = sizeof(temp);
long v;
int n = recvfrom(r, (char *)(&v), sizeof(v), 0, (struct sockaddr *)(&temp), &templen);
if (n != sizeof(v)) return 2;
else if (v != j) fprintf(stderr, "Received: %lu (DROPPED PACKET)\n", v); return 3;
// else fprintf(stderr, "Received: %lu\n", v);
++j;
【问题讨论】:
它不是一个可靠的协议。 @EJP:你观察到它在本地丢包? @Mehrdad 我观察到它在 RFC 中所说的内容以及协议中没有确认和重试的情况。 QED。无需经验观察。 @EJP:我非常明确地说我在问一个实际问题,而不是一个理论问题。即,我正在寻找经验观察,而不是公理观察。所以是的,这是必要的,因为这就是我要问的。 你要解决的实际问题是什么......就像第谷布拉赫和约翰内斯开普勒...... 【参考方案1】:如果我纯粹使用 UDP 进行进程间通信(即在 1 系统,不涉及网络),我可以认为它是可靠的吗?
没有。即使所有通信都在同一主机上完成,UDP 数据包仍可能(有时会)被丢弃。
如果你愿意,你可以自己演示一下;在同一主机上设置两个使用 UDP 套接字的程序,程序 A 将 UDP 数据包发送给程序 B,程序 B 接收并记录它们。 (在 UDP 数据包中包含序列号,以便程序 B 可以轻松判断何时没有收到数据包。
一旦它开始工作并且数据包以合适的速率传输,将一些代码放入程序 B 中,以便它经常调用 sleep(5) (或类似的,这样程序 B 无法在其上调用 recv() UDP 套接字很长一段时间)。您可能会看到,在 sleep() 调用返回后,程序 B 报告某些数据包被跳过——因为当 B 处于睡眠状态时,其 UDP 套接字的传入数据包缓冲区已满,然后网络丢弃了一些数据包堆栈,因为没有地方可以放置它们。
【讨论】:
有趣。您在哪些操作系统中观察到了这种行为? 全部。你不需要遵守 @Mehrdad 你会在任何操作系统下看到它。这是 RAM 空间有限这一事实的自然结果,因此一次只能存储有限数量的 UDP 数据包(等待接收应用程序处理)。 @JeremyFriesner:嗯,我问是因为上次我在 Windows 上尝试了类似的东西,它没有遇到任何队列大小限制——它很高兴地一直发送数据包,直到系统运行记忆。我在问你已经在哪些操作系统上看到过这种情况,所以请回答这个问题。你真的看到它发生了吗?或者这只是一个假设? @Mehrdad 我很确定我已经在 Windows 下看到过它,但是为了 100% 确定我刚刚在我的 Windows 7 机器上设置了一个测试并验证了 Windows 7 确实表现得像我描述的。我唯一一次看到像你在评论中描述的行为是当接收程序有一个单独的 I/O 线程,其工作是分配一个 RAM 缓冲区,recv() 将数据包数据放入其中,然后添加该缓冲区到一个 FIFO 数据结构供主线程稍后处理——在这种情况下,如果主线程以某种方式卡住,FIFO 将无限增长并最终耗尽所有 RAM。以上是关于UDP是IPC的可靠协议吗?的主要内容,如果未能解决你的问题,请参考以下文章