Вопрос:
Я хочу использовать сокет 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 байта), ресивер может получить только те данные, которые были бы проверены на локальном хосте. Если я уменьшу номер в отправителе, например 1024. Приемник по-прежнему получает только верхние 8 Кбайт данных. Если я увеличу номер числа в отправителе до X байтов (X> 8192). Получатель получит верхние данные X Bytes.
Похоже, что минимальный размер пакета Qt UDP для передачи составляет 8192 байта. Приемник всегда получает первый пакет, но не может принимать других.
У меня мало опыта в Qt и сетевом программировании, поэтому я не знаю, правильна ли моя гипотеза или нет. Можете ли вы рассказать мне, как изменить эти коды для поддержки приема пакетов после первого пакета, чтобы я мог передавать большие данные?
Лучший ответ:
После долгой отладки и использования Wireshark для захвата пакетов. Я думаю, что причина этого вопроса – это QUdpSocket. Как и многие другие примеры в Интернете, мой код, вероятно, прав. Но класс QUdpSocket не подходит для передачи больших данных. Поскольку, когда функция слота, подключенная к readyRead(), выполняется, последующие датаграммы не могут запускать ее снова, пока функция не будет выполнена. Поэтому отправитель должен поспать некоторое время после отправки некоторых данных, чтобы ждать функции слота приемника.
Вывод: QUдpSocket Class не является надежным переносом больших данных. Я должен использовать низкоуровневые API-интерфейсы Socket, настраивать некоторые протоколы и проектировать многопроцессорную/многопоточную архитектуру для решения проблемы принципиально. Конечно, использование TCP Sockets – еще один выбор.
Ответ №1
Вероятно, ваша проблема исходит из этой строки:
} while (udpSocket1.hasPendingDatagrams());
Вы ожидаете, что весь набор пакетов будет поставлен в очередь и готов к немедленному получению, но скорее вероятность того, что некоторые из них будут доступны, а позже будет больше. Поэтому вам нужно прослушивать сокет дольше, чем это, и определить, когда другая сторона действительно закончила отправлять данные.