QUdpsocket 在处理前一个数据报时丢失数据报
QUdpsocket losses datagrams while processing previous one
我正在通过 udp 拆分帧 (50Kb) 并将 frameId 添加到数据中,将未打包的图像 (bmp) 数据从一个应用程序 (unity) 发送到另一个 (QT)。
另一方面,我正在尝试集成帧(使用 frameId),在我收集了一张图像的所有帧后,我将其作为图像处理。
如果我只是捕获帧而不处理它们,我会按正确的顺序获取数据
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 缓冲区中?
Where is the problem?? in udp buffer?
问题是,如果套接字的接收缓冲区已满,那么计算机在缓冲区已满时收到的任何 UDP 数据包都将被丢弃。这不是错误,它是 UDP 工作原理的 'feature'。
丢弃的 UDP 数据包只是生活中的一个事实;任何使用 UDP 的程序都必须以某种方式处理丢弃的 UDP 数据包。这里有一些你可以处理它们的方法(并非所有都是相互排斥的):
- 使您的 processTheDatagram() 函数如此高效,以至于它总是returns足够快以至于 UDP 缓冲区永远没有时间填满
- 在您的 QUDPSocket 上调用 setSocketOption(QAbstractSocket::ReceiveBufferSizeSocketOption, someLargeValue) 以为其提供更大的内核接收缓冲区,这将需要更长的时间来填满
- 与其尝试在同一个线程中处理数据报,不如将数据报添加到 FIFO 队列中,让另一个线程完成繁重的工作。这样你的 I/O 线程总是可以自由地快速接收下一个 UDP 数据包。
- 实施某种流量控制或数据包重发算法,以便数据包的发送速度不会超过您的计算机处理它们的速度,或者如果数据包被丢弃,您可以请求再次发送它(尽管如果你走这条路,通常最好只使用 TCP)
- 运行 在更快的计算机上:)
作为对@Jeremy Friesner 的第二个建议的补充:
对于 QUdpSocket:
- 确保调用 setSocketOption 而不是 setReadBufferSize,后者指的是 QAbstractSocket 的内部缓冲区 QUdpSocket 不使用。
- 在 setSocketOption 之前调用 QUdpSocket::bind。
我正在通过 udp 拆分帧 (50Kb) 并将 frameId 添加到数据中,将未打包的图像 (bmp) 数据从一个应用程序 (unity) 发送到另一个 (QT)。 另一方面,我正在尝试集成帧(使用 frameId),在我收集了一张图像的所有帧后,我将其作为图像处理。 如果我只是捕获帧而不处理它们,我会按正确的顺序获取数据
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 缓冲区中?
Where is the problem?? in udp buffer?
问题是,如果套接字的接收缓冲区已满,那么计算机在缓冲区已满时收到的任何 UDP 数据包都将被丢弃。这不是错误,它是 UDP 工作原理的 'feature'。
丢弃的 UDP 数据包只是生活中的一个事实;任何使用 UDP 的程序都必须以某种方式处理丢弃的 UDP 数据包。这里有一些你可以处理它们的方法(并非所有都是相互排斥的):
- 使您的 processTheDatagram() 函数如此高效,以至于它总是returns足够快以至于 UDP 缓冲区永远没有时间填满
- 在您的 QUDPSocket 上调用 setSocketOption(QAbstractSocket::ReceiveBufferSizeSocketOption, someLargeValue) 以为其提供更大的内核接收缓冲区,这将需要更长的时间来填满
- 与其尝试在同一个线程中处理数据报,不如将数据报添加到 FIFO 队列中,让另一个线程完成繁重的工作。这样你的 I/O 线程总是可以自由地快速接收下一个 UDP 数据包。
- 实施某种流量控制或数据包重发算法,以便数据包的发送速度不会超过您的计算机处理它们的速度,或者如果数据包被丢弃,您可以请求再次发送它(尽管如果你走这条路,通常最好只使用 TCP)
- 运行 在更快的计算机上:)
作为对@Jeremy Friesner 的第二个建议的补充:
对于 QUdpSocket:
- 确保调用 setSocketOption 而不是 setReadBufferSize,后者指的是 QAbstractSocket 的内部缓冲区 QUdpSocket 不使用。
- 在 setSocketOption 之前调用 QUdpSocket::bind。