QSocketNotifier: Socket notifiers cannot be enabled or disabled from another thread



  • Hello,
    I am having this trouble since two days ago and I am not sure how solve this error.
    I made a code for a server that can handle multiple connections, my goal is to read in the server messages from a device in the serialPort, send this messages to all the clients connected to my server and, from the clients can send message to the device. To do this, I saw that I need programming a Thread that can handle the multiple connections.
    I made this code:

    myserver.cpp

    #include "myserver.h"
    
    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;
       connect(mipuerto2, SIGNAL(msgChanged()), this, SLOT(getMens()));
       mipuerto2->openSerialPort();
    }
    
    void MyServer::getMens()
    {
        arr2=mipuerto2->getMensaje();
    
        emit mensChanged(&arr2);
    }
    
    void MyServer::sendMens(QByteArray *arraySend)
    {
    mipuerto2->writeMsg(*arraySend);
    }
    
    
    void MyServer::incomingConnection(int socketDescriptor)
    {
    
    qDebug()<<socketDescriptor<<"Connecting... ";
    MyThread *thread=new MyThread(socketDescriptor, this);
    connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
    connect(this, SIGNAL(mensChanged(QByteArray * )), thread, SLOT(getMsg(QByteArray *)));
    connect(thread, SIGNAL(mensajeEnviar(QByteArray * )), this,SLOT(sendMens(QByteArray * )));
    thread->start();
    
    }
    

    mythread.cpp

    #include "mythread.h"
    
    MyThread::MyThread(int ID, QObject *parent) : QThread(parent)
    {
        this->socketDescriptor=ID;
    
    }
    
    void MyThread::run()
    {
    //thread start here
        qDebug()<<socketDescriptor<< " Starting thread";
        socket = new QTcpSocket();
        if(!socket->setSocketDescriptor(this->socketDescriptor)){
            emit error(socket->error());
    
        }
    
        connect(socket, SIGNAL(readyRead()), this, SLOT(readyRead()), Qt::DirectConnection);
        connect(socket, SIGNAL(disconnected()), this, SLOT(disconnected()), Qt::DirectConnection);
    
        qDebug() << socketDescriptor<< " Client Connect";
    
    
    
        exec();
    }
    
    void MyThread::readyRead()
    {
    
        msgSend="";
       // socket->waitForReadyRead(100);
        msgSend=socket->readAll();
    
            qDebug()<<msgSend.toHex();
    emit mensajeEnviar(&msgSend);
    }
    
    void MyThread::disconnected()
    {
        qDebug() << socketDescriptor<< " Disconnected";
    
        socket->deleteLater();
    
        exit(0);
    }
    
    void MyThread::getMsg(QByteArray * array)
    {
    
        socket->write(*array);
        socket->waitForBytesWritten(3000);
    
    }
    

    So everytime that, the serial port read a new group of messages, emit a signal to send them.
    With this code, I can read the messages from the client and send message (I haven't probe with more connections yet), but when I read I get this error in the server console:

    QSocketNotifier: Socket notifiers cannot be enabled or disabled from another thread

    This error appears every time that a new messages arrives to the server from the serial port. Does anyone know what I can do to solve it?
    Thanks.



  • @Dooham I also have this error: QObject: Cannot create children for a parent that is in a different thread.
    (Parent is QNativeSocketEngine(0x52fbc8), parent's thread is MyThread(0x5322f0), current thread is QThread(0x514de0)



  • @Dooham

    Check where you create objects in your thread, beware they are created in run slot.

    See
    https://mayaposch.wordpress.com/2011/11/01/how-to-really-truly-use-qthreads-the-full-explanation/



  • @CP71 Thaks for your answer. I thing that all the QObects that I created are in the run slot. I just created the QTCPSocket and it is in the reun slot in the third line. When I read this article, I tried to use the movetoThread(this) but I didnt work.



  • @Dooham
    You are welcome!
    Where do you declare and use QNativeSocketEngine object?
    I think I don’t see it in your code?



  • @CP71 To be honest, I dont know where is declare. First of all I dont know what is exactly it. I got an example of multithreatings server and adapte it to my trouble. Now, I am trying to change the QTcpSocket from a declare variable to a local variable (I have read that this could solve the problem), but I not sure about how to adapt the function getMsg to read my socket.



  • @Dooham
    sorry!
    I believe is a my stupid question :(
    i think it is created when you create a socket

    https://code.woboq.org/kde/qt4/src/network/socket/qnativesocketengine.cpp.html#_ZN19QNativeSocketEngineD1Ev



  • @CP71 Yeah, seeing that socumntation, I think you are right, but I dont understand why appears that error. I wrote the same code that the example that I saw, and that worked , but when I adapted to my case it failed.



  • @Dooham
    I have a dubt.
    Maybe I’m beeing wrong but I think that your server musn't create TcpSocket but it should waiting a new connection:

    In your server
    QObject::connect( this, SIGNAL(newConnection()), this, SLOT(newConnection()) );

    In newConnection:

    //////////////////////////////////////////////////////////////////////////////////////
    ///
    void MyServer::newConnection()
    {
    QTcpSocket *socket = server->nextPendingConnection();
    if ( socket )
    {
    … doing your procedure
    }
    }

    I don’t see where incomingConnection is called.

    But maybe it is already so.



  • @CP71 I think that is not neccesary,because of the function incomingConnection. When I see this Code I had a similar doubt, but this function is a virtual function of QtcpServer that is called when a newConnection Signal appears. In this code,I just edit the function a bit.
    Maybe the trouble would be that I didnt called the write function from the run, and this could be problematic. In a while, I will try to rewrite the code un order to call the function that write the message from the run


  • Lifetime Qt Champion

    Hi,

    Are you trying to implement a threaded server ? If so, you can take a look at the threaded fortune server example.



  • @SGaist Thanks you, I think this example support my idea, that the trouble is that I dont call the function that write the message from the run function but from a external slot that, in theory dont interact with this routine. Am I right?
    On the other hand, do you know any method to initialize the serial port from the thread just one time (at the begginning of the program)? I have been thinking during the last hour but I dont archive any progress
    Thanks again


  • Lifetime Qt Champion

    What is your exact use of QSerialPort ?



  • @SGaist I read the continuous message that a device (a Pixhawk). Every thing that I receive a package of message ( the serial port send me package of message) in form of QByteArray I send it to a client that can decode them



  • @Dooham That didn't work, I dont know what is the trouble, I have seen that there are two different QThread ID, and that is probably the cause of the issue:
    0_1554190211682_3c2ed1b3-b00e-4493-9839-8182529d1966-image.png
    As you can see, I got the adress of the Thread that I generate with the incomingConnection but, in some point I create an Object that its parent is other QThread.
    I dont know what to do.



  • @Dooham
    I think you don't call addPendingConnection or it seems so

    0_1554194144567_013b5385-d81d-4dd1-be58-d950d072f8e1-image.png



  • @Dooham @CP71 @SGaist Finally I could "solve" the trouble that I had. I had to create other class that has the QTcpSocket, and create that class inside the run function of the thread as a local variable. However I found some trouble with the write method, I dont know how to solve it. The trouble is that dont read the client (with the previous code I could read, the messaged from the client). This is my code:

    myserver.cpp

    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;
      connect(mipuerto2, SIGNAL(msgChanged(QByteArray*)), this, SLOT(getMens(QByteArray*)));
       mipuerto2->openSerialPort();
    }
    
    void MyServer::getMens(QByteArray*array)
    {
    
    
    
        emit mensChanged(array);
    }
    
    void MyServer::sendMens(QByteArray *arraySend)
    {
    mipuerto2->writeMsg(*arraySend);
    }
    
    
    void MyServer::incomingConnection(int socketDescriptor)
    {
    
    qDebug()<<socketDescriptor<<"Connecting... ";
    MyThread *thread=new MyThread(socketDescriptor, this);
    
    qDebug()<<thread;
    connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
    connect(this, SIGNAL(mensChanged(QByteArray * )), thread, SLOT(getMsg(QByteArray *)));
    connect(thread, SIGNAL(mensajeEnviar(QByteArray * )), this,SLOT(sendMens(QByteArray * )));
    
    
    
    thread->start();
    
    }
    
    

    myserialport.cpp

    #include "myserialport.h"
    #include <QObject>
    #include <QtSerialPort/QSerialPort>
    #include <QDebug>
    
    
    MySerialPort::MySerialPort()
    {
        serial = new QSerialPort(this);
        data= "";
    
        connect(serial, SIGNAL(readyRead()), this, SLOT(readData()));
        openSerialPort();
    
    }
    
    void MySerialPort::openSerialPort()
    {
        serial->setPortName("COM4");
        //serial->setBaudRate(QSerialPort::Baud9600);
        serial->setBaudRate(QSerialPort::Baud115200);
        serial->setDataBits(QSerialPort::Data8);
        serial->setParity(QSerialPort::NoParity);
        serial->setStopBits(QSerialPort::OneStop);
        serial->setFlowControl(QSerialPort::NoFlowControl);
        serial->open(QIODevice::ReadWrite);
    
    
    }
    
    void MySerialPort::closeSerialPort()
    {
        if(serial->isOpen()){
            serial->close();
        }
    }
    
    void MySerialPort::readData()
    {
    
       data = serial->readAll();
        dataAux=data.toHex();
        emit msgChanged(&data);
    
    }
    
    QByteArray MySerialPort::getMensaje()
    {
        return data;
    }
    
    void MySerialPort::writeMsg(QByteArray datos)
    {
    
        serial->write(datos);
    
    }
    
    

    mythread.cpp

    #include "mythread.h"
    #include "mysocket.h"
    MyThread::MyThread(int ID, QObject *parent) : QThread(parent)
    {
        this->socketDescriptor=ID;
    
    
    }
    
    void MyThread::run()
    {
        qDebug()<<socketDescriptor<< " Starting thread";
        MySocket socket2(this->socketDescriptor);
        //Revisar mas tarde
        /*if(!socket2.setSocketDescriptor(this->socketDescriptor)){
            emit error(socket->error());
    
        }*/
    
        /*connect(socket2, SIGNAL(readyRead()), this, SLOT(readyRead()), Qt::DirectConnection);*/
    
    
        connect(this, SIGNAL(mensajeRecibido(QByteArray*)), &socket2, SLOT(getMsg(QByteArray*)));
        connect(&socket2, SIGNAL(disconnected()), this, SLOT(disconnected()));
        connect(&socket2, SIGNAL(mensajeEnviarSocket(QByteArray*)), this, SLOT(readyRead(QByteArray*)));
        qDebug() << socketDescriptor<< " Client Connect";
    
    
    
        exec();
    }
    
    void MyThread::readyRead(QByteArray*arraySent)
    {
    
    
        qDebug()<<arraySent->toHex();
        emit mensajeEnviar(arraySent);
    }
    
    void MyThread::disconnected()
    {
        qDebug() << socketDescriptor<< " Disconnected";
    
        //socket->deleteLater();
    
        exit(0);
    }
    
    void MyThread::getMsg(QByteArray * array)
    {
        emit mensajeRecibido(array);
    
    
    }
    

    mysocket.cpp (This is the new class)

    #include "mysocket.h"
    
    MySocket::MySocket(int socketDescriptor)
    {
    socket= new QTcpSocket;
    socket->setSocketDescriptor(socketDescriptor);
    connect(this, SIGNAL(disconnected()), this, SLOT(desconexion()));
    connect(this, SIGNAL(readyRead()), this, SLOT(leerMsg()));
    qDebug()<<"Hola";
    }
    
    void MySocket::leerMsg()
    {
        msgSend="";
        // socket->waitForReadyRead(100);
        msgSend=socket->readAll();
    
        qDebug()<<msgSend.toHex();
        emit mensajeEnviarSocket(&msgSend);
    }
    
    void MySocket::desconexion()
    {
       socket->deleteLater();
    }
    
    void MySocket::getMsg(QByteArray *array)
    {
    
        arr=*array;
        //qDebug()<<arr;
       // qDebug()<<"server a thread";
        socket->write(arr);
        socket->flush();
        socket->waitForBytesWritten(3000);
    }
    
    

    mysocket.h

    #ifndef MYSOCKET_H
    #define MYSOCKET_H
    
    #include <QObject>
    #include <QTcpSocket>
    
    class MySocket:public QTcpSocket
    {
        Q_OBJECT
    public:
        MySocket(int socketDescriptor);
    signals:
        void mensajeEnviarSocket(QByteArray *arraySend);
    
    public slots:
        void leerMsg();
        void desconexion();
        void getMsg(QByteArray *array);
    private:
        QTcpSocket *socket;
        QByteArray arr;
        QByteArray msgSend;
    };
    
    #endif // MYSOCKET_H
    

    With this code, I can read the serial port and sending to the client without troubles (I also tried with the telnet command and two connections, and this could with them). But I can read the messages sent. Another trouble that I saw, is that, when I disconect the client, in the server appears the following error: QAbstractSocket::waitForBytesWritten() is not allowed in UnconnectedState

    Does anyone knows how I can solve this issues?
    Thanks for your help.



  • @Dooham I have solved the trouble with waitforBytesWritten with the function: waitforConnected() that return true if is connected so, I just read if the socket is connected. But I cant read yet.



  • @Dooham
    Hi,
    I quickly watch your code.
    I see a thing that is a bit dangerous or I think so, you emit a pointer and not a copy of data without thread synchronization, don’t you?



  • @Dooham
    And more,
    I think you must call addPendingConnection in your incomingConnection

    void MyServer::incomingConnection(int socketDescriptor)
    {

    addPendingConnection( thread→GetQTcpSocketPointer() )

    thread->start();

    }



  • @CP71 I dont know if this is dangerous or not, but it is easy to change, I think. So I will change it later to pass a QByteArray and not a QByteArray pointer. Related to pendingConnection, I don know if this is necessary or not. I am just going to have a few connection. I proved ths code with three clients and I didnt have troubles. With the exception that I cant send message to the serialport, but is a problem that dont depend of the number of connections. However I saw that the trouble is that the socket dont emit the signal readyRead in the socket of the server when I receive a message from a client.



  • @Dooham
    Ok,
    When we have some problems we say, “the computer has always reason”, well almost always.
    I’m joking ;)

    I already done a TCP Server but I took another road and I hadn't got special problems, so now I haven’t ideas. :(

    If I can, I suggest you to solve one problem at a time, I would start at the end, as per QtcpSocket, to try to understand why readyRead seems not working I should check the following checks:

    • Check with Wireshark or other tools if TCP packets arrive to your device
    • Check by debug text info about QTcpSocket that you have created (e.g. IP of the client)

    Then climb up to TcpServer.

    Sorry



  • @CP71 Dont worry, you are helpful. I will tried to find the trouble, I know that must be in my Code of the server, because in the first Code that I published in this thread I could do It. And in a simpler Code for just one connection server-client It also worked.


Log in to reply
 

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