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

QServer slow down the reading of the serial port



  • Hello,
    I had to write a code for a server that can read a device connected in a serial port (the device is a Pixhawk, a device that sends constantely messages in form of QByteArray) and send this messages to a client software that can decode this messages. On the other hand, I also need send messages to the device from the client.
    I wrote the code with a QThread in order to handle multiple conections. However, when I implement the code with this QThread, I saw that the reading speed slow down (when I had a simple server (just could handle one connection), the reading speed was 75 msg/s and whit the QThread the reading speed is 60 msg/s). This issue happens, independently of the number of clients connected.

    This is the code of my server:

    
    MyServer::MyServer(QObject *parent) : QTcpServer (parent)
    {
    
    }
    
    void MyServer::startServer()
    {
    
        if(!this->listen(QHostAddress::Any, 9999)){
    qDebug()<<"Server not started";
        }else {
    qDebug()<<"Server listening";
        }
    }
    
    void MyServer::startSerialPort()
    {
       mipuerto2 = new MySerialPort;
       msgRec = new MensajeRecibido;
       msgSent = new MensajeEnviar;
      connect(mipuerto2, SIGNAL(msgChanged(QByteArray*)), this, SLOT(getMens(QByteArray*)));
      connect(mipuerto2, SIGNAL(msgChanged(QByteArray*)), this, SLOT(idMensaje(QByteArray*)));
      connect(msgSent, SIGNAL(tienesMensaje(QString*)), this, SLOT(setRecibido(QString *)));
      mipuerto2->openSerialPort();
    }
    
    QString MyServer::recibido()
    {
       return _recibido;
    }
    
    void MyServer::getMens(QByteArray*array)
    {
    
    
    
        emit mensChanged(array);
    }
    
    void MyServer::sendMens(QByteArray *arraySend)
    {
    
        mipuerto2->writeMsg(*arraySend);
        _recibido+= QString("\n %1").arg(QString(arraySend->toHex()));
        msgSent->getData(*arraySend);
        msgSent->descifrarMsg2();
    
        qDebug()<<"Mensaje enviado al puerto";
    }
    
    void MyServer::idMensaje(QByteArray *arrayIden)
    {
    
        msgRec->getData(*arrayIden);
        msgRec->descifrarMsg2();
    }
    
    void MyServer::setRecibido(QString *_mensaje)
    {
        _recibido+=*_mensaje;
        emit recibidoChanged();
    
    }
    
    
    
    
    void MyServer::incomingConnection(int socketDescriptor)
    {
    
    qDebug()<<socketDescriptor<<"Connecting... ";
    
    socket = new MySocket(socketDescriptor);
    QThread *thread = new QThread;
    qDebug()<<thread->currentThreadId();
    connect(this, SIGNAL(mensChanged(QByteArray*)), socket, SLOT(getMsg(QByteArray*)));
    
    connect(socket, SIGNAL(mensajeEnviarSocket(QByteArray*)), this, SLOT(sendMens(QByteArray*)));
    connect(socket, SIGNAL(disconnected()),thread, SLOT(quit()) );
    connect(socket, SIGNAL(disconnected()), socket, SLOT(deleteLater()));
    connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
    connect(thread, SIGNAL(started()), socket, SLOT(funcionamiento()));
    
    socket->moveToThread(thread);
    thread->start();
    
    
    
    

    mySocket (for the server)

    #include "mysocket.h"
    
    MySocket::MySocket(int socketDescriptor)
    {
    ID=socketDescriptor;
    }
    
    
    void MySocket::readyRead()
    {
        qDebug()<<"Mensaje entrante";
        msgSend="";
       socket->waitForReadyRead(100);
        msgSend=socket->readAll();
    
        qDebug()<<msgSend.toHex();
        emit mensajeEnviarSocket(&msgSend);
    
    }
    
    void MySocket::funcionamiento()
    {
        socket= new QTcpSocket;
        estado=socket->setSocketDescriptor(ID, QAbstractSocket::ConnectedState, QIODevice::ReadWrite);
        connect(this, SIGNAL(disconnected()), this, SLOT(desconexion()));
        connect(socket, SIGNAL(readyRead()), this, SLOT(readyRead()));
        qDebug()<<"Hola";
        qDebug()<<socket->state();
        qDebug()<<socket->openMode();
    }
    
    void MySocket::desconexion()
    {
       socket->close();
       socket->deleteLater();
    }
    
    void MySocket::getMsg(QByteArray *array)
    {
    if(socket->waitForConnected(1000)){
        arr=*array;
        //qDebug()<<arr;
       // qDebug()<<"server a thread";
        socket->write(arr);
        socket->flush();
        //socket->waitForBytesWritten(3000);
    }
    }
    

    mysocket(for the client)

    #include "mytcpsocket.h"
    
    MyTcpSocket::MyTcpSocket(QObject *parent) :
        QObject(parent)
    {
    }
    
    void MyTcpSocket::doConnect()
    {
        if(cont==0){
            cont=1;
    
        socket = new QTcpSocket(this);
        data="";
        connect(socket, SIGNAL(connected()),this, SLOT(connected()));
        connect(socket, SIGNAL(disconnected()),this, SLOT(disconnected()));
        connect(socket, SIGNAL(bytesWritten(qint64)),this, SLOT(bytesWritten(qint64)));
        connect(socket, SIGNAL(readyRead()),this, SLOT(readyRead()));
    
        Conexiones();
        qDebug() << "connecting...";
    
        // this is not blocking call
    
        socket->connectToHost("localhost", 9999);
    
        // we need to wait...
        if(!socket->waitForConnected(5000))
        {
            qDebug() << "Error: " << socket->errorString();
        }
    
        }else{
            qDebug()<<"Dispositivo conectado";
        }
    
    }
    
    void MyTcpSocket::desconectar()
    {
        if(cont==1){
       socket->close();
       cont=0;
       // socket->abort();
        }
    }
    
    void MyTcpSocket::writeMsg()
    {
        if(cont==1){
    msgSend=msgEnviar.CodificarEnviar();
    socket->write(msgSend);
    //socket->flush();
    //socket->waitForBytesWritten(3000);
        }
    }
    
    void MyTcpSocket::Conexiones()
    {
    
        connect(&mensajeRec,SIGNAL(vibrationChanged2()), this,SLOT(setVibrations()) );
        connect(&mensajeRec, SIGNAL(attitudChanged2()), this, SLOT(setAttitud()));
        connect(&mensajeRec, SIGNAL(globalPositionIntChanged2()), this, SLOT(setGlobalPosition()));
        connect(&mensajeRec, SIGNAL(powerStatusChanged2()),this, SLOT(setBattery()));
        connect(&mensajeRec,SIGNAL(windChanged2()), this, SLOT(setWind()));
        connect(&mensajeRec,SIGNAL(missionAckChanged2()), this, SLOT(setMissionAck()));
    
    
    }
    
    
    
    
    void MyTcpSocket::connected()
    {
        qDebug() << "connected...";
    
    
        //socket->write("Hola");
    }
    
    void MyTcpSocket::disconnected()
    {
        qDebug() << "disconnected...";
    }
    
    void MyTcpSocket::bytesWritten(qint64 bytes)
    {
        qDebug() << bytes << " bytes written...";
    }
    
    void MyTcpSocket::readyRead()
    {
    
        data = socket->readAll();
    
    
        mensajeRec.getData(data);
        mensajeRec.descifrarMsg2();
    }
    
    
    
    
    void MyTcpSocket::setVibrations()
    {
        _vibrations=mensajeRec.devolverMensaje();
        emit vibrationsChanged();
    
    }
    
    QString MyTcpSocket::vibrations()
    {
        return _vibrations;
    }
    
    void MyTcpSocket::setAttitud()
    {
       _attitud=mensajeRec.devolverMensaje();
       emit attitudChanged();
    }
    
    QString MyTcpSocket::attitud()
    {
        return _attitud;
    }
    
    
    //Estas funciones sirven para usar Global Position
    void MyTcpSocket::setGlobalPosition()
    {
        _globalPosition=mensajeRec.devolverMensaje();
      emit globalPositionChanged();
    }
    
    QString MyTcpSocket::globalPosition()
    {
        return _globalPosition;
    }
    
    //Estas funciones sirven para obtener el Wind
    void MyTcpSocket::setWind()
    {
        _wind=mensajeRec.devolverMensaje();
       emit windChanged();
    }
    
    QString MyTcpSocket::wind()
    {
        return _wind;
    }
    
    QString MyTcpSocket::missionAck()
    {
        return _missionAck;
    }
    
    void MyTcpSocket::setBattery(){
        _battery=mensajeRec.devolverMensaje();
        emit batteryChanged();
    }
    
    void MyTcpSocket::setMissionAck()
    {
        _missionAck=mensajeRec.devolverMensaje();
        emit missionAckChanged();
    }
    QString MyTcpSocket::battery(){
        return _battery;
    }
    
    

    In the code of the socket for the client, the last functions is for the UI made in QML.
    Does anyone know why it happens this?
    Thaks you all.


  • Qt Champions 2019

    @Dooham said in QServer slow down the reading of the serial port:

    I wrote the code with a QThread in order to handle multiple conections

    There is really no need for a thread as Qt is asynchronous...



  • @jsulm Do you mean using a QThreadPool?
    I am not sure if this would work for my case



  • I have discovered that this just happen when I am reading the serial port before the connection. If I connect the client to the server and then I start to read the serial port the reading speed is normal.


  • Qt Champions 2019

    @Dooham said in QServer slow down the reading of the serial port:

    Do you mean using a QThreadPool?

    No. Just use asynchronous Qt APIs (signals/slots).



  • @jsulm I tried with these changes:

    myserver.cpp

    qDebug()<<socketDescriptor<<"Connecting... ";
    socket = new MySocket(socketDescriptor);
    connect(this, SIGNAL(mensChanged(QByteArray*)), socket, SLOT(getMsg(QByteArray*)));
    
    connect(socket, SIGNAL(mensajeEnviarSocket(QByteArray*)), this, SLOT(sendMens(QByteArray*)));
    

    mysocket.cpp

    
    MySocket::MySocket(int socketDescriptor)
    {
    ID=socketDescriptor;
    funcionamiento();
    }
    
    

    But the reading speed slow down as it does in the qthread. I dont know if you refer to this type of code.


  • Qt Champions 2019

    @Dooham By slow down do you mean that readyRead slot is called less often?
    Also, why do you call waitForReadyRead() there? If readyRead slot is called then there is already something to read.



  • @jsulm I dont know if the trouble is that I call the readyRead slot less frequent. I am not sure where is the trouble, but it could be. I tried to remove the waitForReadyRead but it didnt solve my problem.
    The serial port give me QByteArray that contains some messages, when I receive a new package I emit a signal from the class MySerialPort (I didnt write the code in this thread, but I can write it if you want), that activate a slot with another signal that bring connect the server class with mySocket. Then, I write the QbyteArray that I received in MySerialPort in the socket to send it to the client. When the client receives a new QByte Array from the socket, it extract the different messages and decode it to get the information. At this time is when I measure the reading speed, because when I decode a message I show on the screen the number of messages that I received at this moment. This is the process that is slowed down when I connect the server-client (and just if I was reading the serial port in the server, if I connect first and the I open the serial port, the reading speed is normal).



  • I dont know why, but if I set the conexion between server and client first and then I call the function startSerialPort(), the reading speed is the normal. But this method just works with the first conexion. The second conexion already experiment the decrease of the reading speed.

    void MyServer::startSerialPort()
    {
       mipuerto2 = new MySerialPort;
       msgRec = new MensajeRecibido;
       msgSent = new MensajeEnviar;
     connect(mipuerto2, SIGNAL(msgChanged(QByteArray*)), this, SLOT(getMens(QByteArray*)));
       connect(mipuerto2, SIGNAL(msgChanged(QByteArray*)), this, SLOT(idMensaje(QByteArray*)));
      connect(msgSent, SIGNAL(tienesMensaje(QString*)), this, SLOT(setRecibido(QString *)));
      mipuerto2->openSerialPort();
    }
    
    
    
    qDebug()<<socketDescriptor<<"Connecting... ";
    
    socket = new MySocket(socketDescriptor);
    controlador++;
    QThread *thread = new QThread;
    qDebug()<<thread->currentThreadId();
    connect(this, SIGNAL(mensChanged(QByteArray*)), socket, SLOT(getMsg(QByteArray*)));
    
    connect(socket, SIGNAL(mensajeEnviarSocket(QByteArray*)), this, SLOT(sendMens(QByteArray*)));
    connect(socket, SIGNAL(disconnected()),thread, SLOT(quit()) );
    connect(socket, SIGNAL(disconnected()), socket, SLOT(deleteLater()));
    connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
    connect(thread, SIGNAL(started()), socket, SLOT(funcionamiento()));
    connect(socket, SIGNAL(disconnected), this, SLOT(desconectar()));
    
    socket->moveToThread(thread);
    thread->start();
    if(controlador==1){
        startSerialPort();
    }else if (controlador>1) {
    
        mipuerto2->closeSerialPort();
        delete mipuerto2;
        startSerialPort();
    }