Server is losing bytes
-
Hi!
The following code sends a header and a file to a server:
bool add_audio(const std::string & p_root_files , const std::string & p_server , uint16_t p_port , mother_data_ptr p_mother , babies_data::iterator p_baby , audios_data::iterator p_audio) { QTcpSocket _sender; _sender.connectToHost(QString(p_server.c_str()) ,p_port); if (!_sender.waitForConnected()) { return false; } // header { QByteArray _data; QDataStream _block(&_data, QIODevice::WriteOnly); // mother id _block << static_cast<quint32>(p_mother->get_id()); // passwd QString _passwd(p_mother->get_passwd().c_str()); _block << _passwd; // cmd id _block << static_cast<quint16>(commands::add_audio); // _sender.write(_data); // baby id _block << static_cast<quint16>(p_baby->get_id()); // desc QString _desc(p_audio->get_description().c_str()); qDebug() << "desc = " << _desc << ", " << "desc size = " << _desc.size(); //_block << static_cast<QString::size_type>(_desc.size()); _block << _desc; // audio id _block << static_cast<quint32>(p_audio->get_id()); // extension QString _extension(p_audio->get_extension().c_str()); _block << _extension; _sender.write(_data); qDebug() << "header with " << _data.size(); _sender.waitForBytesWritten(); } // audio { quint64 _amount_sent = 0; QString _file_name(file_string(). define_audio_full_file_path(p_root_files ,p_mother ,p_baby ,p_audio)); qDebug() << "file name = " << _file_name; QFile _file(_file_name); _file.open(QFile::ReadOnly); const qint64 _amount = 10 * 1024; //qint16 _counter = 0; while (true) { QByteArray _data = _file.read(_amount); if (_data.size() == 0) { break;} //qDebug() << ++_counter << ": data size = " << _data.size(); _sender.write(_data); _amount_sent += _data.size(); _sender.waitForBytesWritten(); } _file.close(); qDebug() << _amount_sent << " bytes sent"; } //_sender.close(); _sender.disconnectFromHost(); qDebug() << "##### audio sent ####"; return true; }
The 'ConnectionHandler::read_data' is the slot for the 'readyRead' signal:
void ConnectionHandler::read_data() { if (m_connection->bytesAvailable()) { QByteArray _data = m_connection->readAll(); qDebug() << "incoming size = " << _data.size(); if (m_first_read) { qDebug() << "data = " << _data ; QDataStream _in(&_data, QIODevice::ReadOnly); // mother quint32 _mother; _in >> _mother; // passwd QString _passwd; _in >> _passwd; qDebug() << "passwd = " << _passwd ; quint16 _cmd; _in >> _cmd; qDebug() << "cmd = " << _cmd; switch (_cmd) { case 1: m_cmd_handler = new FileReader(this , _mother , _in); QByteArray _tmp; _in >> _tmp; qDebug() << "tmp size = " << _tmp.size(); (*m_cmd_handler)(_tmp); m_first_read = false; break; } } else { if (m_cmd_handler) { (*m_cmd_handler)(_data); } } } }
The 'FileReader' constructor is:
FileReader::FileReader (QObject * p_parent , quint32 p_mother , QDataStream & p_stream ) : CmdHandler(p_parent) , m_mother(p_mother) , m_baby() , m_desc() , m_audio() , m_extension() , m_file() , m_amount_received(0){ // baby id p_stream >> m_baby; qDebug() << "baby = " << m_baby; // description p_stream >> m_desc; qDebug() << "m_desc = " << m_desc << ", " << "m_desc.size() = " << m_desc.size(); // audio id p_stream >> m_audio; qDebug() << "audio = " << m_audio;// << ", pos = " << p_index; p_stream >> m_extension; qDebug() << "extension = " << m_extension;// << ", pos = " << p_index; QString _file_name(QString("/var/tmp/") + QString::number(m_mother) + "_" + QString::number(m_baby) + "_" + QString::number(m_audio) + "." + m_extension); qDebug() << "file name = " << _file_name; m_file.setFileName(_file_name); if (m_file.exists()) { m_file.remove(); } }
And the 'FileReader::operator()(const QByteArray &)' is:
bool FileReader::operator()(const QByteArray & p_data) { QByteArray::size_type _data_size = p_data.size(); quint64 _amount_to_write = static_cast<quint64>(_data_size); if (_amount_to_write > 0) { const char * _data = p_data.data(); m_file.open(QIODevice::Append); quint64 _amount_written = m_file.write(_data, _amount_to_write); m_file.close(); m_amount_received += _amount_to_write; qDebug() << "amount received = " << m_amount_received << ", to write = " << _amount_to_write << ", " << "writen = " << _amount_written; return (_amount_written == _amount_to_write); } return false; }
When the transmission finishes, the file at the server side is always smaller than the one at the client side.
I really can not figure out what I am doing wrong.
Would please someone point it out?
Thanks a lot!!!
-
readyRead
is emitted not only when all the data is available to be read but also when you have chunks (partials) of data available.
inread_data
when you callm_connection->readAll();
you are assuming all the data is already received but that's not always the case.Handling this depends on the version of Qt, in Qt5 it's easier using QDataStream transactions, in Qt4 you have to do it manually via checking
bytesAvailable()
.Take a look at the
readFortune()
method of the fortune client example
Qt4: http://doc.qt.io/qt-4.8/qt-network-fortuneclient-example.html
Qt5: http://doc.qt.io/qt-5/qtnetwork-fortuneclient-example.htmlP.S.
sending a password in plain text over an unencrypted socket is NEVER a good idea