【问题标题】:How to send and receive large data using Qt UDP socket?如何使用 Qt UDP 套接字发送和接收大数据?
【发布时间】:2013-03-06 18:26:40
【问题描述】:

我想使用 Qt UDP(不是 TCP)套接字来传输文件。 所以我写了这样的代码:

发件人

QFile file1(QString::fromStdString(filedir));
QByteArray bytes;
file1.open(QIODevice::ReadOnly);
QTextStream in(&file1);
while (!in.atEnd()) {
    bytes = in.read(8192).toAscii();
    udpSocket.writeDatagram(bytes, QHostAddress(ip), port.toInt());
}

接收者

udpSocket1.bind(ui->sendPort->text().toInt());
connect(&udpSocket1,SIGNAL(readyRead()),this,SLOT(listenfile()));

void Widget::listenfile() {
    QFile file("received.txt");
    file.resize(0);
    file.open(QIODevice::Append);
    QTextStream out(&file);
    do {
        QByteArray data;
        data.resize(udpSocket1.pendingDatagramSize());
        udpSocket1.readDatagram(data.data(),data.size());
        QString str=data.data();
        ui->textBrowser1->append(str);
        out << data;
    } while (udpSocket1.hasPendingDatagrams());
}

当我发送小文件时,没有问题。 但是,如果我想发送大文件(> 8192 字节),即使在 localhost 上测试,接收方也只能获得前 8KB 的数据。 如果我减少发送方的大小数字,例如 1024。接收方仍然只能获得前 8KB 的数据。 如果我将发送方的大小数增加到 X 字节(X > 8192)。接收方将获得前 X 字节数据。

似乎要传输的 Qt UDP 数据包的最小大小是 8192 字节。接收者总是得到第一个数据包,但不能接收其他数据包。

我对Qt和网络编程的经验很少,所以我不知道我的猜想是否正确。你能告诉我如何更改这些代码以支持在第一个数据包之后接收数据包,以便我可以传输大数据吗?

【问题讨论】:

    标签: qt sockets network-programming udp


    【解决方案1】:

    您的问题可能来自这一行:

    } while (udpSocket1.hasPendingDatagrams());
    

    您希望整个数据包集排队并准备好立即接收,但更有可能的是一些数据包将可用,稍后会有更多数据包可用。所以你需要比这更长的时间监听socket,并确定对方何时真正完成发送数据。

    【讨论】:

    • 感谢您的回复。你的意思是我应该永远使用另一个线程循环来处理数据报,还是其他一些简单的方法?我认为将 readyRead() 信号连接到 listenfile() 插槽可以永远监听套接字。因为当发送方发送第二个文件时,接收方也可以得到最上面的数据报,而不是忽略。 (也许我错了)
    • 对...您需要在发出 readyRead() 信号时调用您的阅读代码。问题将是检测一个文件何时结束而另一个文件何时开始。如果需要,您可以在数据包前面使用魔术字节来做到这一点。 IE,当有更多数据包到来时,总是在一个数据包前面放置一个值为 0x00 的 1 字节数据包,当它是最后一个数据包时,在数据包前面放置一个 0x01,这样你就知道它是文件的结尾,下一个数据包将是第二个文件的开始。但记得在保存之前去掉那个字节:-)
    • 然而,这听起来不像是 UDP 的工作。我不确定你为什么在发送大文件时强制使用 UDP。这就是 TCP 的意义所在。通常,您应该以 1400 字节的数据包发送块,这样 UDP 就不需要分段。然后,整个问题就是使用 UDP,您可能会丢失数据包并且不知道它。或者你甚至可以得到一个包两次!想象一下这会对您传输的文件产生什么影响!同样,你真的应该使用 TCP。
    【解决方案2】:

    经过长时间调试,使用Wireshark抓包。我认为问题的原因是 QUdpSocket 本身。像 Internet 上的许多其他示例一样,我的代码可能是正确的。但是 QUdpSocket 类不适合传输大数据。因为当连接到readyRead()的slot函数正在执行时,后续的数据报无法再次触发,直到函数执行完毕。所以发送方必须在发送一些数据后休眠一段时间,等待接收方的 slot 函数。

    结论是QUdpSocket类是不可靠的传输大数据。我应该使用底层的Socket API,定制一些协议,设计多进程/多线程架构,从根本上解决问题。当然使用 TCP Sockets 是另一种选择。

    【讨论】:

    • 我遇到同样的问题已经有一段时间了,它真的让我患上了癌症。在用 QUdpSocket 尝试了许多不同的方法并经历了一段相当痛苦的时期之后,我最终决定了同样的事情:QUdpSocket 不适合处理高速数据流。低级winsock udp 线程往往能更好地解决问题。但这真的,真的可悲。我希望 Qt 想出一个解决这个严重问题的方法。
    猜你喜欢
    • 2013-11-19
    • 2011-09-24
    • 2015-02-21
    • 1970-01-01
    • 1970-01-01
    • 2010-11-13
    • 2017-09-27
    • 1970-01-01
    • 2012-02-16
    相关资源
    最近更新 更多