Приветствую всех :-)
Передаю по сети файлы, используя QTcpSocket и многопоточность. Соответственно, файл перед отправкой надо разбить на кусочки, на получателе - собрать.
Нашёл тему -
http://www.prog.org.ru/topic_10870_0.html, где уже есть прекрасные готовые куски.
Для разбивки использовал код от
BRE (спасибо :-), что на второй странице; для сборки - код от
TukiNov (тоже спасибо :-)
В итоге, у меня это выглядит так:
Разборка и отправка:void threadClient::run()
{
//qDebug () << "threadClient::run()";
QTcpSocket tcpSocket;
if (!tcpSocket.setSocketDescriptor(socketDescriptor)) {
//qDebug () << "error(tcpSocket.error())";
return;
}
tcpSocket.waitForConnected();
QByteArray block;
QFile file(filePath);
QDataStream read(&file);
file.open(QFile::ReadOnly);
//отправка служебной информации
QByteArray bArray;
QDataStream dStream(&bArray, QIODevice::WriteOnly);
dStream.setVersion(QDataStream::Qt_4_5);
dStream << quint64(file.size());
dStream << CRC32(filePath);
//qDebug () << "CRC sended: " << CRC32(filePath);
dStream << filePath;
dStream << inPath;
tcpSocket.write(bArray);
tcpSocket.flush();
ong 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 += tcpSocket.write(ba, sizeof(char)*l);
//!!Вот этот qDebug
qDebug () << "block.size: " << i;
i++;
//!!
tcpSocket.flush();
if (-1 == lBytes){
qWarning() << "Error";
tcpSocket.close();
return;
}
float procentage = ((float)lBytes / file.size()) * 100;
emit setProcentage((int)procentage);
}//while(!readEnd())
free((void*)ch);
Приём и сборка:void FortuneThread::run()
{
qDebug () << "FortuneThread::run()";
QTcpSocket tcpSocket;
if (!tcpSocket.setSocketDescriptor(socketDescriptor)) {
emit error(tcpSocket.error());
return;
}
quint64 fileSize;
quint32 CRCgeted;
QString getedFilePath;
QString usedFilePath;
tcpSocket.waitForReadyRead(-1);
QByteArray bArray;
QDataStream dStream(&bArray, QIODevice::ReadWrite);
dStream.setVersion(QDataStream::Qt_4_5);
bArray = tcpSocket.readAll();
dStream >> fileSize;
qDebug () << "fileSize" << fileSize;
dStream >> CRCgeted;
qDebug () << "CRCgeted" << CRCgeted;
dStream >> getedFilePath;
qDebug () << "getedFilePath" << getedFilePath;
dStream >> usedFilePath;
qDebug () << "usedFilePath" << usedFilePath;
//Приём и сборка файла
QFile save(usedFilePath);
save.open(QFile::WriteOnly);
QDataStream write(&save);
write.setVersion(QDataStream::Qt_4_5);
long int lBytesDone = 0; //Пока ничего не приняли
long int lSize = fileSize;
qDebug () << "lSize" << lSize;
long int lBytes;
while (lBytesDone < lSize){//Пока приняли меньше, чем указано
//Ожидаем данные
//qDebug () << "In while";
lBytes = 0;
while (lBytes == 0) lBytes = tcpSocket.waitForReadyRead(-1);
//qDebug () << "tcpSocket readyread";
if (-1 == lBytes){//Если произошла ошибка сокета, то
qWarning("-----TFileServer: Aborting download.");
//qDebug () << "EROOR!!";
tcpSocket.close();
return;
}//if (-1 == lBytes)
QByteArray tmp = tcpSocket.readAll();
lBytes += write.writeRawData(tmp.data(), tmp.size());
//qDebug () << "lBytes: " << lBytes;
lBytesDone += tmp.size();
//qDebug () << "lBytesDone" << lBytesDone;
float procentage = ((float)lBytes / fileSize) * 100;
//qDebug () << "procentage" << procentage;
//emit setProcentage((int)procentage);
}//while (lBytesDone < lSize)
save.close();
qDebug () << "File saved";
exec();
}
На маленьких файлах (до мегабайта) всё работает прекрасно. При попытке передать файл в мегабайт - файл записан не полностью.
Тогда я вставил строчки:
qDebug () << "block.size: " << i;
i++;
Просто для того, чтобы проверить, всё ли записывается на отправителе.
И оно заработало.
Если закомментить qDebug - не работает. Если просто выводить "blockSize" без i - не работает.
Если оставить - всё прекрасно передаётся (пробовал на файлах в 700 мегов включительно).
Объяснить это кроме как It's magic! я не могу. разве что, qDebug даёт какую-то минимальную задержку, которая нужна tcpSocket'у для write перед flush...
Так что, оно, конечно, сейчас работает, но является, несомненно, невероятным костылём.
Не подскажете ли, в чём именно дело (ну оооочень интересно) и как костыль убрать.
Заранее спасибо :-)