UDP是一种可靠的进程间通信协议吗?

4
如果我仅在一个系统中(即没有网络涉及)使用UDP进行进程间通信,我可以认为它是可靠的吗?还是我仍然需要担心数据包丢失等问题?请注意,这是一个实际问题,而非理论问题。如果答案在不同的操作系统中有所不同,请说明原因,尤其是包括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;
        }
    }
}

1
它不是任何事情的可靠协议。 - user207421
1
@EJP:我非常明确地表明我正在提出一个实际问题,而不是理论问题。也就是说,我正在寻找经验观察,而不是公理观察。所以是的,这是必要的,因为那就是我所问的。 - user541686
1
你试图解决的实际问题是什么......就像是Tycho Brahe和Johannes Kepler一样。 - CristiFati
@CristiFati:我正在努力学习。不确定您所说的比较是什么意思。我没有要求任何人将任何东西与UDP进行比较。 - user541686
我再次声明,无论谁删除我的正确陈述,寻找关于正式行为的轶事证据都是不科学的。答案在RFC中,要么有,要么没有,而它没有,因此没有可靠性。你不能仅依靠经验观察。UDP具有所需的行为,可靠性并不是其中的一部分。 - user207421
显示剩余4条评论
1个回答

11
如果我仅在同一系统中使用UDP进行进程间通信(即没有涉及网络),那么可以认为它是可靠的吗?
不可以。即使所有通信都在同一主机上进行,UDP数据包仍然可能会被丢弃。
如果您愿意,您可以自行演示此过程;在同一主机上设置两个使用UDP套接字的程序,其中A程序发送UDP数据包到接收它们并记录它们的B程序。(在UDP数据包中包含序列号,以便程序B可以轻松地知道何时未接收到某个数据包)。
一旦这个设置工作正常,并且数据包以合理的速率传输,请将一些代码放入程序B中,以便定期调用sleep(5)(或类似操作,使得程序B无法在其UDP套接字上调用recv()函数相当长一段时间)。 您可能会发现,在sleep调用返回后,程序B报告有一些数据包被跳过--因为当B处于睡眠状态时,其UDP套接字的输入数据缓冲区已满,然后由于没有地方放置它们,网络堆栈丢弃了一些数据包。

有趣。你观察到这种行为在哪些操作系统中? - user541686
3
所有的。你不需要观察。 - CristiFati
2
@Mehrdad,你会在任何操作系统下都看到它。这是由于RAM空间有限的自然结果,因此一次只能存储有限数量的UDP数据包(等待接收应用程序处理)。 - Jeremy Friesner
1
@JeremyFriesner:我问这个问题是因为上次在Windows上尝试类似的操作时,并没有遇到任何队列大小限制 - 它一直快乐地发送数据包,直到系统内存耗尽。我想知道你见过哪些操作系统出现这种情况,请回答我的问题。你真的见过它发生吗?还是只是一个假设? - user541686
请注意,Windows文档中的SO_RCVBUF setsockopt()参数强烈暗示了在Windows下套接字的接收缓冲区是固定大小的(否则允许用户设置缓冲区大小就没有意义):https://msdn.microsoft.com/en-ca/library/windows/desktop/ms740476(v=vs.85).aspx - Jeremy Friesner
显示剩余6条评论

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