PDA

View Full Version : QTcpSocket - Cannot create children for a parent that is in a different thread



Begginer
17th April 2016, 00:17
Hello,
I am new to QT.
In my project I have QTcpServer with multithreading. I need to implement that when server recieve something from one client(client is GUI aplication), send it to all clients except the one who sent data. Problem occurs when I call socket->write(data) in function sendToAllClients() in server.cpp. I got following:
QObject:Cannot create children for the parent that is in different thread qt.

Could anyone please help me with this. I was searching about on google, but whatever I tried it doesn't work.
Thanks a lot.


My code is below:

mythread.cpp


MyThread::MyThread(qintptr ID, QObject *parent) :
QThread(parent)
{
this->socketDescriptor = ID;
this->disconnectedSocket=-1;
}

void MyThread::run()
{
socket = new QTcpSocket();

if(!socket->setSocketDescriptor(this->socketDescriptor))
{
emit error(socket->error());
return;
}

connect(socket, SIGNAL(readyRead()), this, SLOT(readyRead()), Qt::DirectConnection);
connect(socket, SIGNAL(disconnected()), this, SLOT(disconnected()));

exec();
}

void MyThread::readyRead()
{
readyToRead=true;

if(readyToRead==true)
emit ReadyToReadAllSockets(); //ReadyToReadAllSockets() is signal I wrote to make connection between thread and server.

}


server.cpp



Server::Server(QObject *parent) :
QTcpServer(parent)
{
connect(this,SIGNAL(newConnection()),this,SLOT(num OfClients()));


}

void Server::incomingConnection(qintptr socketDescriptor)
{
clients_list.append(socketDescriptor);
MyThread *thread = new MyThread(socketDescriptor, this);
threads.append(thread);
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
connect(thread, SIGNAL(finished()), this, SLOT(clientDisconnect()));
connect(thread, SIGNAL(finished()), this, SLOT(removeClientFromList()));
connect(thread, SIGNAL(ReadyToReadAllSockets()), this, SLOT(sendToAllClients()));


thread->start();

}

void Server::sendToAllClients()
{

qDebug()<< "Writing in sockets....";
MyThread* thread;
QByteArray Data;


for(int i=0;i<threads.size();i++)
{
if(threads.at(i)->getIfReady())
{

thread=threads.at(i);
Data = threads.at(i)->getSocket()->readAll();
threads.at(i)->setReady(false);

}
}

for(int i=0;i<threads.size();i++)
{
if(threads.at(i)!=thread)
{
socket=threads.at(i)->getSocket();
socket->write(Data); // this is where occur error

}
}

}

anda_skoa
17th April 2016, 12:48
This is very wrong even if you hadn't gotten an error.

There is no protection what so ever against concurrent access of either the sockets or the readyToRead flag (assuming setReady changes that).

If the idea is to use cross-thread signal/slots to savely transfer data between threads, then you need to refrain from accessing data directly.

If you want to do it with direct method calls, these methods need to use appropriately synchronized data access procedures.

In general you should make sure that you really need this to be multithreaded.

Cheers,
_

Begginer
17th April 2016, 13:58
Could you please give me some guidelines, how can I implement that server can communicate with multiple clients simultaneosly, and that server can comunicate with all clients, without using threads..And what is the best way to solve this type of project.. My client is GUI aplication, and server needs to be console application.. I started learning QT before 1 week, and I don't know a lot about what I can do, and which way is the most correct.

Sorry if my english is not good, I hope you understand me.
Thanks you a loot.
Best regards

anda_skoa
17th April 2016, 14:25
If you don't do any heavy processing on the client data you should be able to do this single threaded, which makes it a lot easier to achieve.

My suggestion would be:
- use a client handler object, a bit like now but not deriving from QThread, just from QObject.
- this class has a signal that is emitted when data arrives on the respective client connection. A bit like you do now, but actually having the data as the signal argument
- this class also has a slot with a compatible signature, that sends the given data to the client

- your server needs a list of these objects

- when you get a new incoming connection, create such a client handler instance
- iterate over the list and connect each list entry's signal with the new objects's slot and the new object's signal with the list entry's slot
- add the new object to the list

So when data comes in on any connection, it is emitted by that connection's handler.
All other handlers are connected to that signal and will send the data to their clients.

Cheers,
_

Begginer
18th April 2016, 08:05
Thanks you a lot, I fixed that and it works now...
Best regards.