3
votes

I want to use Qt UDP (not TCP) socket to transfer file. So I write code like this:

Sender

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());
}

Receiver

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());
}

When I send small file, there is no problem. However, if i want to send large file (> 8192 bytes), the receiver can only get the top 8KB data even tested on localhost. If I decrease the size number in sender, such as 1024. The receiver still only gets the top 8KB data. If I increase the size number in sender to X bytes (X > 8192). The receiver will get the top X Bytes data.

It seems like the minimum size of Qt UDP packet to transfer is 8192 bytes. The receiver always gets the first packet, but can not receive others.

I have little experience in Qt and network programming, so I don't know whether my conjecture is right or not. Can you tell me how to change these codes to support receiving packets after the first packet so I can transfer large data?

2

2 Answers

4
votes

After debugging a long time and using Wireshark to capture packets. I think the reason for the issue is QUdpSocket itself. Like many other examples on the Internet, my code probably is right. But the QUdpSocket Class is not appropriate for transfering large data. Because when the slot function connected to readyRead() is executing, subsequent datagrams can not trigger it again until the function is done. So the sender must sleep a while after sent some data to wait the receiver's slot function.

The conclusion is QUdpSocket Class is not a reliable to transfer large data. I should use low level Socket APIs, customize some protocols and design multi-process/multi-thread architecture to solve the problem fundamentally. Of course using TCP Sockets is another choice.

3
votes

Your issue probably comes from this line:

} while (udpSocket1.hasPendingDatagrams());

You're expecting the entire set of packets to be queued up and ready to be received at once, but it's more likely that some will be available and later more will. So you need to listen to the socket longer than that and determine when the other side actually has finished sending data.