Qt отправить файл через TCP

Я делаю клиентский сервер TCP файлов внутри одного приложения.

Прежде всего, я отправляю имена файлов и файлов на 50000 байт.

Клиент:

void client::sendFile(QString path)
{ QDataStream out(cl); QFile toSend(path); if (toSend.open(QIODevice::ReadOnly)) { int s = 0; QFileInfo fileInfo(toSend.fileName()); QString fileName(fileInfo.fileName()); out << fileName; while (!toSend.atEnd()) { QByteArray rawFile; rawFile = toSend.read(50000); out << rawFile; qDebug() << "ToSend"<
<p>... это правильно, я думаю</p> <p> Сервер (слот ReadyRead):</p> <pre class="prettyprint linenums">void server::receive() { QTcpSocket *sender = (QTcpSocket*) this->sender(); QDataStream in(sender); QString fName; in >> fName; QFile newFile("D:\\"+fName); if (newFile.open(QIODevice::WriteOnly)) { while(sender->bytesAvailable()) { QByteArray z; in >> z; newFile.write(z); qDebug () << "Received " << z.size(); } newFile.close(); } } </pre> <p>... и здесь проблема: в <code>while сломана после первого itteration.

Посмотрите:

ToSend 50000
ToSend 50000
ToSend 50000
ToSend 31135
Total: 181135
Received 50000

Как вы видите, только 1 блок получил вместо 4.

Как это исправить? Почему bytesAvailable возвращает 0, если это не так? Было бы хорошо знать, что это хороший подход к получению файлов по tcp или нет :)

3 ответа

Вероятно, потому, что есть только один пакет. Перед отправкой данных вам необходимо настроить переговоры о размере файла. Затем просто подождите, пока все данные будут переданы. BytesAvailable() возвращает false, как только обрабатываются первые 50k данных. Если вы снова вызове bytesAvailable() снова, подождите 1 секунду, вы получите еще один пакет.

Внесите 4 байта "Размерный пакет" перед отправкой данных и проверьте полученные байты.

Итак, ваш протоколл будет:

  • Размер пакета
  • Пакет данных
  • n-times Data Packet

Другой вариант - иметь предопределенный конечный пакет, но это может быть опасно, если ваш файл может содержать этот пакет в необработанных данных. Если вы можете обеспечить, чтобы ваши данные не содержали ваш конечный пакет, вы в конечном итоге реализуете протокол как:

  • Пакет данных
  • n-times Data Packet
  • Конечный пакет


Вы должны "изобрести" протокол, который позволяет получателю знать, сколько данных будет передано. bytesAvailable показывает только количество байтов, которые были получены до сих пор и которые могут быть прочитаны из потока, но не знает, сколько данных передатчик отправит в будущем.

См. Здесь очень простой пример того, как это сделать.


Проблема заключается в вашей петле, которая ждет байтовAvailable().

Слот ReadyRead предназначен для обработки этого. Когда ваш слот вызывается, прочитайте количество доступных байтов и обработайте их. Затем вы должны вернуться из функции.

Когда доступно больше данных, вы снова получите вызов в функции slotRead.

Конечно, это означает, что вам нужно будет буферизовать данные между последовательными вызовами, и рекомендуется запустить процесс, отправив заголовок, сколько байтов ожидает сервер для всего файла. После того, как сервер скопировал это количество байтов, он может затем записать в новый файл.

licensed under cc by-sa 3.0 with attribution.