QUdpSocket在处理前一个数据报时会丢失数据报。

3

我正在通过UDP将非压缩的图像(bmp)数据从一种应用程序(unity)发送到另一种应用程序(QT),将数据分为多个帧(每个帧大小为50Kb)并添加帧ID。

在另一端,我尝试使用帧ID整合这些帧,并在收集完一个图像的所有帧之后将其作为图像进行处理。

如果我只是捕获这些帧而不进行处理,则可以按正确的顺序获取数据。

void Server::readPendingDatagrams()
{
    if (udpSocket->hasPendingDatagrams()) {
        QByteArray datagram;
        datagram.resize(udpSocket->pendingDatagramSize());
        QHostAddress sender;
        quint16 senderPort;

        udpSocket->readDatagram(datagram.data(), datagram.size(),
                                &sender, &senderPort);
        qDebug()<<datagram[0]; //frameId
        //processTheDatagram(datagram);
    }
}

我在控制台看到了"1 2 3 4 5 1 2 3 4 5 1 2 3 4 5",但是如果我取消注释processTheDatagram(datagram); 我会得到"1 3 4 1 2 4 2 4 5 2 3 5",在处理之前的数据报时会丢失数据。 问题出在哪里?是在udp缓冲区中吗?


你能提供 processTheDatagram 函数的代码吗? - David van rijn
1
另外,我不想成为那个人,但你考虑过使用TCP吗?它似乎更适合你的需求,因为这就是TCP的用途(将消息按顺序放入)。因为不能保证你的数据包会按顺序到达。 - David van rijn
你是否考虑过开启一个线程来处理每一个数据报? - Elkvis
1
这很正常。你选择使用UDP,对吧?处理数据包丢失吧。 - Kuba hasn't forgotten Monica
2个回答

7
问题在哪里?是在UDP缓冲区吗?
问题在于,如果套接字的接收缓冲区已满,则计算机在缓冲区已满时接收到的任何UDP数据包都将被丢弃。 这不是错误,而是UDP工作方式的“特性”。
丢失UDP数据包只是生活中的一个事实; 使用UDP的任何程序都必须以某种方式处理丢失的UDP数据包。以下是您可以处理它们的一些方法(不是所有互斥):
1. 使您的processTheDatagram()函数如此高效,以至于它总是足够快地返回,以便UDP缓冲区永远没有时间填满 2. 在您的QUDPSocket上调用setSocketOption(QAbstractSocket :: ReceiveBufferSizeSocketOption,someLargeValue),以为其提供更大的内核接收缓冲区,这需要更长的时间才能填满 3. 不要尝试在同一线程中处理数据报,只需将数据报添加到FIFO队列中,让另一个线程处理繁重的工作。 这样,您的I / O线程始终可以快速接收下一个UDP数据包。 4. 实现某种流量控制或数据包重发算法,以便数据包不会比计算机处理它们的速度更快,或者如果数据包丢失,您可以请求重新发送它们(尽管如果您走这条路,通常最好使用TCP) 5. 运行在更快的计算机上 :)

2
作为对@Jeremy Friesner第二个建议的补充:
对于QUdpSocket:
  1. 确保您调用setSocketOption而不是setReadBufferSize,后者是QAbstractSocket的内部缓冲区,而QUdpSocket不使用。
  2. 在调用setSocketOption之前,请调用QUdpSocket :: bind。

请在设置套接字选项之前调用QUdpSocket :: bind。这完全解决了接收缓冲区限制问题,现在我已经没有丢包了。 - Gary

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