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.
    in read_data when you call m_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.html

    P.S.
    sending a password in plain text over an unencrypted socket is NEVER a good idea



  • Thanks for your time!

    I'll take a closer look to the 'fortune*' examples.

    The password is being sent plain text here, but it will be ciphered in the final code.

    Thanks!


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.