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. -
@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.
-
@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
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 -
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 -
What is your exact use of QSerialPort ?
-
@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:
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 @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.