Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

do multiple calls to write of QTcpSocket/QWebSocket overwrite previous bytes which are not yet written?



  • hello there. sorry to bother you again.
    I have a few questions about QTcpSocket and QWebSocket

    When the write function of QTcpSocket is called, it doesn't write all bytes instantaneously but stores it in some sort of buffer, right? So When I call write multiple times while there are still some bytes to be written, are previous bytes which are not yet written are overwritten?

    Also, multiple calls to sendBinaryMessage of QWebSocket overwrite previous bytes which are not yet written?

    if bytes are not overwritten then in which order does the QByteArray objects are read by the client ? for example in the following situation on the server with QWebSocket

    socket.sendBinaryMessage(MyQByteArray1);
    socket.sendBinaryMessage(MyQByteArray2);
    socket.sendBinaryMessage(MyQByteArray3);
    

    will binaryMessageReceived signals contain QByteArray objects which are the same as those on the server-side in sequence? something like?

    binaryMessageReceived(MyQByteArray1);
    binaryMessageReceived(MyQByteArray2);
    binaryMessageReceived(MyQByteArray3);
    

    or do they arrive in random order?



  • Hi,
    I done some testing with QWebSocket and QWebSocketServer. basically I send 3 Images from client to server of the following size 5 times without waiting for bytes to write

    $ du -h *.jpg                             
    35M     c0.jpg
    56K     c1.jpg
    30M     c.jpg
    

    client.cpp:-

    #include <QApplication>
    #include <QImage>
    #include <QWebSocket>
    #include <QDataStream>
    #include <QLabel>
    #include <QAbstractSocket>
    #include <QFile>
    
    void onConnected(QWebSocket *socket,QString str){
        QFile imgfile(str);
        imgfile.open(QIODevice::ReadOnly);
    
        QByteArray buf;
        QDataStream stream(&buf,QIODevice::WriteOnly);
    
        socket->sendBinaryMessage(imgfile.readAll());
        socket->flush();
    }
    
    int main(int argc, char *argv[]) {
        QApplication a(argc, argv);
        QWebSocket *socket = new QWebSocket;
        socket->open(QUrl("ws://127.0.0.1:1718"));
    
        QObject::connect(socket, &QWebSocket::disconnected, [socket]() {
            qDebug() << socket->errorString();
        });
    
        QObject::connect(socket,&QWebSocket::connected,[socket]{
            for(int i=0; i<5;i++){
                onConnected(socket,"c.jpg");
                onConnected(socket,"c0.jpg");
                onConnected(socket,"c1.jpg");
            }
        });
    
        return a.exec();
    }
    

    server.cpp:-

    #include <QApplication>
    #include <QWebSocket>
    #include <QHostAddress>
    #include <QWebSocketServer>
    #include <QLabel>
    #include <QFile>
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
    
        QWebSocketServer server(QStringLiteral("My server"),QWebSocketServer::SslMode::NonSecureMode);
    
        if(!server.listen(QHostAddress::Any,1718)){
            qDebug() << server.errorString() ;
            return -1;
        }
    
        qDebug() << server.serverUrl().toString();
    
        QObject::connect(&server, &QWebSocketServer::newConnection,[&server](){
    
            static int i=100;
    
            qDebug() << "new connection";
            QWebSocket *pSocket = server.nextPendingConnection();
    
            QObject::connect(pSocket, &QWebSocket::binaryMessageReceived, [](const QByteArray &rawimg){
                auto img = QImage::fromData(rawimg,"JPG");
                QLabel *myLabel = new QLabel;
                myLabel->setPixmap(QPixmap::fromImage(img));
                myLabel->show();
                QFile file(QString::number(i++));
                file.open(QFile::WriteOnly);
    
                file.write(rawimg);
            });
        });
    
        return a.exec();
    }
    

    When I run this program, I can see with the help of title name <server*> of windows and new images in server directory, that images are displayed and written on disk in order in which they were sent from the client.

    This marks my original question answered. So I am marking this as solved

    But btw when I ran server and client, something weird happened.
    when I ran server and client, my laptop became unresponsive for a minute. I couldn't even reach tty to kill server and client. the audio was still playing in the meantime. after a minute, it became responsive again. Then I killed the server and client and got this (I always leave it running in background) :-

    Screenshot_20200224_003741.png

    it nearly filled my RAM and on top of that, it also consumed 6GB of the swap. my swap doesn't even get filled with 1KB normally. is this normal ? am I doing something wrong?


  • Qt Champions 2019

    @noone said in do multiple calls to write of QTcpSocket/QWebSocket overwrite previous bytes which are not yet written?:

    So When I call write multiple times while there are still some bytes to be written, are previous bytes which are not yet written are overwritten?

    No, why should this happen?



  • @Christian-Ehrlicher I guess this should not happen. So I should not write until the previous bytes is written? I am really new this stuff and so much confused


  • Lifetime Qt Champion

    @noone

    Hi
    On most devices, the sending buffer (in the network layer) is big enough
    that you should never have to worry about that and just send as you like.
    It should never overwrite anything.

    The things you send will/should come in the same order as when you send it.



  • @mrjj So does it mean I can call write() multiple times without polling bytesToWrite() ?


  • Lifetime Qt Champion

    @noone
    Yes I would think so unless the WebSocket protocol has some limitation which i think the docs would
    have mentioned then. Or maybe if your message is extremely huge.



  • @mrjj

    if your message is extremely huge.

    I want to send some data from the QSqlDatabase along with multiple (Q)images, they might be in KBs or In MBs. If I serialize multiple QImages with QDatastream then it would easily become more than ~20MB


  • Lifetime Qt Champion

    @noone
    Hi
    That should work fine.
    I'm not that familiar with WebSocket protocol if it also will issue multiple
    binaryMessageReceived signal pr message if the message is large or if that is handled internally and will first trigger binaryMessageReceived signal when all is received.
    You should test it out with one and see.



  • Hi,
    I done some testing with QWebSocket and QWebSocketServer. basically I send 3 Images from client to server of the following size 5 times without waiting for bytes to write

    $ du -h *.jpg                             
    35M     c0.jpg
    56K     c1.jpg
    30M     c.jpg
    

    client.cpp:-

    #include <QApplication>
    #include <QImage>
    #include <QWebSocket>
    #include <QDataStream>
    #include <QLabel>
    #include <QAbstractSocket>
    #include <QFile>
    
    void onConnected(QWebSocket *socket,QString str){
        QFile imgfile(str);
        imgfile.open(QIODevice::ReadOnly);
    
        QByteArray buf;
        QDataStream stream(&buf,QIODevice::WriteOnly);
    
        socket->sendBinaryMessage(imgfile.readAll());
        socket->flush();
    }
    
    int main(int argc, char *argv[]) {
        QApplication a(argc, argv);
        QWebSocket *socket = new QWebSocket;
        socket->open(QUrl("ws://127.0.0.1:1718"));
    
        QObject::connect(socket, &QWebSocket::disconnected, [socket]() {
            qDebug() << socket->errorString();
        });
    
        QObject::connect(socket,&QWebSocket::connected,[socket]{
            for(int i=0; i<5;i++){
                onConnected(socket,"c.jpg");
                onConnected(socket,"c0.jpg");
                onConnected(socket,"c1.jpg");
            }
        });
    
        return a.exec();
    }
    

    server.cpp:-

    #include <QApplication>
    #include <QWebSocket>
    #include <QHostAddress>
    #include <QWebSocketServer>
    #include <QLabel>
    #include <QFile>
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
    
        QWebSocketServer server(QStringLiteral("My server"),QWebSocketServer::SslMode::NonSecureMode);
    
        if(!server.listen(QHostAddress::Any,1718)){
            qDebug() << server.errorString() ;
            return -1;
        }
    
        qDebug() << server.serverUrl().toString();
    
        QObject::connect(&server, &QWebSocketServer::newConnection,[&server](){
    
            static int i=100;
    
            qDebug() << "new connection";
            QWebSocket *pSocket = server.nextPendingConnection();
    
            QObject::connect(pSocket, &QWebSocket::binaryMessageReceived, [](const QByteArray &rawimg){
                auto img = QImage::fromData(rawimg,"JPG");
                QLabel *myLabel = new QLabel;
                myLabel->setPixmap(QPixmap::fromImage(img));
                myLabel->show();
                QFile file(QString::number(i++));
                file.open(QFile::WriteOnly);
    
                file.write(rawimg);
            });
        });
    
        return a.exec();
    }
    

    When I run this program, I can see with the help of title name <server*> of windows and new images in server directory, that images are displayed and written on disk in order in which they were sent from the client.

    This marks my original question answered. So I am marking this as solved

    But btw when I ran server and client, something weird happened.
    when I ran server and client, my laptop became unresponsive for a minute. I couldn't even reach tty to kill server and client. the audio was still playing in the meantime. after a minute, it became responsive again. Then I killed the server and client and got this (I always leave it running in background) :-

    Screenshot_20200224_003741.png

    it nearly filled my RAM and on top of that, it also consumed 6GB of the swap. my swap doesn't even get filled with 1KB normally. is this normal ? am I doing something wrong?


  • Lifetime Qt Champion

    Hi
    It sounds like you have a memory leak somewhere.

    Things like
    QLabel *myLabel = new QLabel; << you assign it no parent so it won't be deleted by the parent.

    You could use
    myLabel->setAttribute(Qt::WA_DeleteOnClose);

    If it pops up the image and you close it by pressing X

    Its should not normally use all your memory and 6GB swap :)

    oh, the image is 35M !!!
    ok so I guess its just the QLabel not being deleted and it gets a copy of the image so
    you dont have to send those 3 images many times to eat lots of memory :)



  • after removing the lines:-

    auto img = QImage::fromData(rawimg);
    QLabel *myLabel = new QLabel;
    myLabel->setPixmap(QPixmap::fromImage(img));
    myLabel->show();
    

    it works perfectly with more than 20*3 images