Название: передать файл через QTcpSocket
Отправлено: Gomerd от Ноябрь 25, 2013, 15:31
Доброго времени суток. Задача написать клиент-серверное приложение и передачу файла. Набрел на тему http://www.prog.org.ru/topic_17556_0.html (http://www.prog.org.ru/topic_17556_0.html) вроде все хорошо: Клиент: sendFile = new QFile(ui->fileLabel->text()); QFileInfo fileInfo(sendFile->fileName()); QString fileName(fileInfo.fileName());
socket->waitForConnected();
QByteArray block;
QDataStream read(sendFile); sendFile->open(QFile::ReadOnly);
//отправка служебной информации
QByteArray bArray; QDataStream dStream(&bArray, QIODevice::WriteOnly); dStream.setVersion(QDataStream::Qt_4_5);
dStream << quint64(sendFile->size()); // dStream << CRC32(filePath); // //qDebug () << "CRC sended: " << CRC32(filePath); // dStream << filePath; // dStream << inPath;
socket->write(bArray); socket->waitForBytesWritten();
long int lBytes = 0; char ch [1024]; ch[1023] = '\0'; int i=0; while(!read.atEnd()){ int l = read.readRawData(ch, sizeof(char)*1023); QByteArray ba(ch, sizeof(char)*l);
lBytes += socket->write(ba, sizeof(char)*l); socket->waitForBytesWritten();
if (-1 == lBytes){ qWarning() << "Error"; socket->close();
return; }
} free((void*)ch); Сервер: QTcpSocket* socket = (QTcpSocket*)sender(); quint64 fileSize; QString fileName; QByteArray receivedLine;
socket->waitForReadyRead(-1);
QByteArray bArray; QDataStream dStream(&bArray, QIODevice::ReadWrite); dStream.setVersion(QDataStream::Qt_4_5); bArray = socket->readAll();
dStream >> fileSize; dStream >> fileName; dStream >> receivedLine;
QFile receivedFile("E:/test/1.txt"); receivedFile.open(QFile::WriteOnly); QDataStream write(&receivedFile); write.setVersion(QDataStream::Qt_4_5);
long int lBytesDone = 0; long int lSize = fileSize; long int lBytes;
while (lBytesDone < lSize) { lBytes = 0; while (lBytes == 0) lBytes = socket->waitForReadyRead(-1); QByteArray tmp = socket->readAll(); lBytes += write.writeRawData(tmp.data(), tmp.size()); lBytesDone += tmp.size(); }
receivedFile.close(); } Однако при получении последнего блока данных приложение зависает на этой строчке: while (lBytes == 0) lBytes = socket->waitForReadyRead(-1); Если передавать большой файл, то записывает все кроме последнего блока, если передается файл в пару кб то он сразу зависает. В чем может быть проблема?
Название: Re: передать файл через QTcpSocket
Отправлено: LisandreL от Ноябрь 25, 2013, 15:43
Передаёте fileSize и данные. Читаете fileSize, fileName, receivedLine и данные. Удивляетесь почему полученных данных меньше чем отосланных. Не удивляйтесь - они в fileName, receivedLine.
Название: Re: передать файл через QTcpSocket
Отправлено: Gomerd от Ноябрь 25, 2013, 15:54
Передаёте fileSize и данные. Читаете fileSize, fileName, receivedLine и данные. Удивляетесь почему полученных данных меньше чем отосланных. Не удивляйтесь - они в fileName, receivedLine.
Потерялось в процессе ковыряния кода. Подправил как было Клиент: dStream << quint64(sendFile->size()); dStream << fileName; + данные сервер: dStream >> fileSize; dStream >> fileName; +данные. Ошибка остается.
Название: Re: передать файл через QTcpSocket
Отправлено: LisandreL от Ноябрь 26, 2013, 15:03
bArray = socket->readAll(); Вот тут проверьте сколько байтов получаете.
Название: Re: передать файл через QTcpSocket
Отправлено: Gomerd от Ноябрь 26, 2013, 23:17
Спасибо, уже разобрался:)
Название: Re: передать файл через QTcpSocket
Отправлено: felixdesouza от Февраль 13, 2014, 17:07
Та же беда. Разваливается передача.
Название: Re: передать файл через QTcpSocket
Отправлено: LisandreL от Февраль 14, 2014, 08:21
Та же беда. Разваливается передача.
Группа программистов-экстрасенсов спешит вам на помощь.
Название: Re: передать файл через QTcpSocket
Отправлено: felixdesouza от Февраль 14, 2014, 09:26
Простите великодушно. Отправитель: QFile *sendFile = new QFile(...имя файла...); QFileInfo fileInfo(sendFile->fileName());
QDataStream read(sendFile); sendFile->open(QFile::ReadOnly); read.setVersion(QDataStream::Qt_5_1);
//отправка служебной информации
QByteArray bArray; QDataStream dStream(&bArray, QIODevice::WriteOnly); dStream.setVersion(QDataStream::Qt_5_1);
dStream << quint64(sendFile->size()); dStream << fileInfo.fileName();
pSocket->write(bArray); pSocket->waitForBytesWritten();
long int lBytes = 0; char ch[1024]; ch[1023] = '\0'; int i=0; while(!read.atEnd()) { int l = read.readRawData(ch, sizeof(char)*1023); QByteArray ba(ch, sizeof(char)*l);
lBytes = pSocket->write(ba, sizeof(char)*l);
pSocket->waitForBytesWritten(); qDebug()<<"ba.size()"<<ba.size(); if (-1 == lBytes) { qWarning() << "Error"; pSocket->close();
return; } } free((void*)ch);
pSocket->close(); Получатель quint64 fileSize; QString fileName;
QByteArray bArray; QDataStream dStream(&bArray, QIODevice::ReadWrite); dStream.setVersion(QDataStream::Qt_5_1);
pSocket.waitForReadyRead(-1); bArray = pSocket.readAll();
dStream >> fileSize; dStream >> fileName;
emit doUpdateUI(QString::number(fileSize)); emit doUpdateUI(fileName);
QFile saveFile("C:/"+fileName); saveFile.open(QFile::WriteOnly); QDataStream write(&saveFile); write.setVersion(QDataStream::Qt_5_1);
long int lBytesDone = 0; long int lSize = fileSize; long int lBytes;
while (lBytesDone < lSize) { lBytes = 0;
while (lBytes == 0) { lBytes = pSocket.waitForReadyRead(-1); } if (-1 == lBytes) {//Если произошла ошибка сокета, то qDebug () << "EROOR!!"; pSocket.close(); return; }//if (-1 == lBytes)
QByteArray tmp = pSocket.readAll(); qDebug()<<"tmp.size();"<<tmp.size();
lBytes += write.writeRawData(tmp.data(), tmp.size()); lBytesDone += tmp.size(); }
saveFile.close(); Имя файла и размер доходят и читаются. А файл считывается не правильно. Видимо что-то случилось...
Название: Re: передать файл через QTcpSocket
Отправлено: felixdesouza от Февраль 18, 2014, 14:17
Та же беда. Разваливается передача.
Группа программистов-экстрасенсов спешит вам на помощь. аууууу... Экстрасенсы....
Название: Re: передать файл через QTcpSocket
Отправлено: Bepec от Февраль 18, 2014, 14:20
А какой файл передаёте? бинарный?
Название: Re: передать файл через QTcpSocket
Отправлено: felixdesouza от Февраль 18, 2014, 14:24
Пробовал текстовый, zip и avi.
1 случай из 20 удачный.
Название: Re: передать файл через QTcpSocket
Отправлено: LisandreL от Февраль 18, 2014, 14:39
Сравните их побайтно, где несовпадение. Вижу варианты а) bArray = pSocket.readAll(); - можете кроме длины и имени и часть файла прихватить уже. б) pSocket->close(); - возможно сокет закрывается раньше, чем вы всё считали. Не помню точно в Qt нормально ли тут на принимающей стороне всё считаться. Ну и вот это точно ошибка: C++ (Qt) free((void*)ch);
Хотя к вашей проблеме едва ли относится.
Название: Re: передать файл через QTcpSocket
Отправлено: felixdesouza от Февраль 18, 2014, 14:43
а) bArray = pSocket.readAll(); - можете кроме длины и имени и часть файла прихватить уже.
Только что-то сюда капнул. Убрал передачу метаданных. Передаётся и принимается правильный размер файла, т.е. файл правильного размера. Осталось красиво его записать на диск.
Название: Re: передать файл через QTcpSocket
Отправлено: felixdesouza от Февраль 18, 2014, 15:19
Вроде работает. Надо после записи метаданных flush сокету сделать на клиенте. Спасибо.
Название: Re: передать файл через QTcpSocket
Отправлено: iCast от Декабрь 01, 2014, 01:21
Ребят, вот тоже взял этот код, немного убрал что не нужно, но программа уходит в вечный цикл. Клиент отправляет файлvoid MyClient::slotSendToServer() {
QFile *sendFile = new QFile("C:\\Users\\1\\Desktop\\2.exe"); //QFileInfo fileInfo(sendFile->fileName()); //QString fileName(fileInfo.fileName());
socket->waitForConnected();
QDataStream read(sendFile); sendFile->open(QFile::ReadOnly);
//отправка служебной информации
QByteArray bArray; QDataStream dStream(&bArray, QIODevice::WriteOnly); dStream.setVersion(QDataStream::Qt_4_8);
dStream << quint64(sendFile->size()-sizeof(quint64));
socket->write(bArray); socket->waitForBytesWritten();
long int lBytes = 0; char ch [1024]; ch[1023] = '\0'; int i=0; while(!read.atEnd()){ int l = read.readRawData(ch, sizeof(char)*1023); QByteArray ba(ch, sizeof(char)*l); lBytes += socket->write(ba, sizeof(char)*l); qDebug()<<"l:" << lBytes; socket->waitForBytesWritten(); if (-1 == lBytes){ qWarning() << "Error"; socket->close();
return; }
} qDebug()<<"sendFile->size(): "<<sendFile->size(); //free((void*)ch);
}
Сервер принимаетvoid MyServer::slotReadClient() // считывает сообщение от клиента { QTcpSocket* socket = (QTcpSocket*)sender(); quint64 fileSize; QString fileName; QByteArray receivedLine;
socket->waitForReadyRead(-1);
QByteArray bArray; QDataStream dStream(&bArray, QIODevice::ReadWrite); dStream.setVersion(QDataStream::Qt_4_8); bArray = socket->readAll();
dStream >> fileSize; qDebug()<<"recive file size: "<<fileSize;
QFile receivedFile("C:\\Users\\1\\Desktop\\folder\\2.exe"); receivedFile.open(QFile::WriteOnly); QDataStream write(&receivedFile); write.setVersion(QDataStream::Qt_4_8);
long int lBytesDone = 0; long int lSize = fileSize; long int lBytes; qDebug()<<"lSize: "<<lSize; while (lBytesDone < lSize) { lBytes = 0; while (lBytes == 0) lBytes = socket->waitForReadyRead(-1); QByteArray tmp = socket->readAll(); lBytes += write.writeRawData(tmp.data(), tmp.size()); lBytesDone += tmp.size(); qDebug()<<"l:" << lBytesDone; }
receivedFile.close(); }
Дебаг показал что здесь проблема while (lBytes == 0) lBytes = socket->waitForReadyRead(-1); расскажите поподробнее как происходит передача файла и как решить проблему. После зависания я закрываю программу и вижу что клиент отправил столько: l: 789756 l: 789864 sendFile->size(): 789864 А сервер получил столько: l: 787710 l: 788733 l: 788841 Программа неожиданно завершилась.
|